~ubuntu-branches/ubuntu/vivid/debmake/vivid-proposed

« back to all changes in this revision

Viewing changes to debmake/gen.py

  • Committer: Package Import Robot
  • Author(s): Osamu Aoki
  • Date: 2013-05-11 12:36:02 UTC
  • Revision ID: package-import@ubuntu.com-20130511123602-0l48hgab7r7vgzwk
Tags: upstream-4.0.0
Import upstream version 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python3
 
2
# vim:se tw=0 sts=4 ts=4 et ai:
 
3
import os, re, sys, glob
 
4
import debmake.copyright
 
5
 
 
6
"""
 
7
Copyright © 2013 Osamu Aoki
 
8
 
 
9
Permission is hereby granted, free of charge, to any person obtaining a
 
10
copy of this software and associated documentation files (the "Software"),
 
11
to deal in the Software without restriction, including without limitation
 
12
the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
13
and/or sell copies of the Software, and to permit persons to whom the
 
14
Software is furnished to do so, subject to the following conditions:
 
15
 
 
16
The above copyright notice and this permission notice shall be included
 
17
in all copies or substantial portions of the Software.
 
18
 
 
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 
20
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
21
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 
22
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 
23
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 
24
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 
25
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
26
"""
 
27
 
 
28
#######################################################################
 
29
def debian(para):
 
30
    source_format(para)
 
31
    source_local_options(para)
 
32
    patches_series(para)
 
33
    compat(para)
 
34
    rules(para)
 
35
    README_Debian(para)
 
36
    changelog(para)
 
37
    copyright(para)
 
38
    control(para)
 
39
    install(para)
 
40
    installdocs(para)
 
41
    docbase(para)
 
42
    manpages(para)
 
43
    if para['extra']:
 
44
        extra(para)
 
45
    else:
 
46
        print('I: run "debmake -x" to get more template files', file=sys.stderr)
 
47
    if os.getcwd() != para['cwd']:
 
48
        print('I: upon return to the shell, current directory becomes {}'.format(para['cwd']), file=sys.stderr)
 
49
        print('I: please execute "cd {0}"'.format(os.getcwd()), file=sys.stderr)
 
50
        print('I: before building binary package with dpkg-buildpackage (or debuild, pdebuild, sbuild, ...).', file=sys.stderr)
 
51
    return
 
52
 
 
53
#######################################################################
 
54
# mkdir -p path
 
55
def mkdirp(path):
 
56
    return os.makedirs(path, exist_ok=True)
 
57
 
 
58
#######################################################################
 
59
# cat >file and cat >>file
 
60
def writefile(para, file, text, append=False, end='\n'):
 
61
    if append:
 
62
        f = open(file, 'a')
 
63
    else:
 
64
        if not para['overwrite'] and os.path.isfile(file) and os.stat(file).st_size != 0:
 
65
            # skip if a file exists and non-zero content
 
66
            print('I: File already exits, skipping: {}'.format(file), file=sys.stderr)
 
67
            return
 
68
        f = open(file, 'w')
 
69
    print(text, file=f, end=end)
 
70
    if append:
 
71
        print('I: File written: {} (append)'.format(file), file=sys.stderr)
 
72
    else:
 
73
        print('I: File written: {}'.format(file), file=sys.stderr)
 
74
    f.close()
 
75
    return
 
76
 
 
77
#######################################################################
 
78
# sed-like
 
79
def subst(para, text):
 
80
    subst = {
 
81
        '@PACKAGE@': para['package'],
 
82
        '@UCPACKAGE@': para['package'].upper(),
 
83
        '@YEAR@': para['year'],
 
84
        '@FULLNAME@': para['fullname'],
 
85
        '@EMAIL@': para['email'],
 
86
        '@SHORTDATE@': para['shortdate'],
 
87
    }
 
88
    for k in subst.keys():
 
89
        text = text.replace(k, subst[k])
 
90
    return text
 
91
 
 
92
#######################################################################
 
93
# find $(pwd) -type f
 
94
def find_files():
 
95
    matches = []
 
96
    for root, dirname, filenames in os.walk('./'):
 
97
            if dirname[:6] != 'debian':
 
98
                for filename in filenames:
 
99
                    matches.append(os.path.join(root, dirname, filename))
 
100
    return matches
 
101
 
 
102
#######################################################################
 
103
def source_format(para):
 
104
    mkdirp('debian/source')
 
105
    if para['native']:
 
106
        writefile(para, 'debian/source/format', '3.0 (native)')
 
107
    else:
 
108
        writefile(para, 'debian/source/format', '3.0 (quilt)')
 
109
    return
 
110
 
 
111
#######################################################################
 
112
def source_local_options(para):
 
113
    mkdirp('debian/source')
 
114
    msg = '''\
 
115
#### Uncomment some of the following lines if you wish :-) See dpkg-source(1)
 
116
#unapply-patches
 
117
#abort-on-upstream-changes
 
118
'''
 
119
    writefile(para, 'debian/source/local-options', msg)
 
120
    return
 
121
 
 
122
#######################################################################
 
123
def patches_series(para):
 
124
    mkdirp('debian/patches')
 
125
    msg = '''\
 
126
# This is manually managed by users with dquilt (quilt(1) wrapper)
 
127
# See http://www.debian.org/doc/manuals/maint-guide/modify.en.html#quiltrc
 
128
# Also this may be updated by dpkg-source(1) when making a package.
 
129
'''
 
130
    writefile(para, 'debian/patches/series', msg)
 
131
    return
 
132
 
 
133
#######################################################################
 
134
def compat(para):
 
135
    msg = para['compat']
 
136
    writefile(para, 'debian/compat', msg)
 
137
    return
 
138
 
 
139
#######################################################################
 
140
def rules(para):
 
141
    if len(para['debs']) == 1:
 
142
        p = para['debs'][0]['package'] # first binary package name
 
143
    else:
 
144
        p = 'tmp'
 
145
    build_dir = 'debian/' + p
 
146
    ###################################################################
 
147
    # build_mode independent portion
 
148
    msg = '''\
 
149
#!/usr/bin/make -f
 
150
# uncomment to enable verbose mode for debhelper
 
151
#DH_VERBOSE = 1
 
152
# uncomment to exclude VCS paths
 
153
#DH_ALWAYS_EXCLUDE=CVS:.svn:.git
 
154
 
 
155
%:
 
156
'''
 
157
 
 
158
    ###################################################################
 
159
    # dh $@: main build script of debhelper v9
 
160
    if para['dh_with'] == set([]):
 
161
        msg += '\tdh $@\n'   # no dh_with
 
162
    else:
 
163
        msg += '\tdh $@ --with "{}"\n'.format(','.join(para['dh_with']))
 
164
 
 
165
    ###################################################################
 
166
    # override build script of debhelper v9
 
167
    ###################################################################
 
168
    if 'python3' in para['dh_with']:
 
169
        # line tail // are meant to be / in debian/rule
 
170
        # make sure to keep tab code for each line (make!)
 
171
        msg += '''\
 
172
 
 
173
# special work around for python3 (#538978 and #597105 bugs)
 
174
PY3REQUESTED := $(shell py3versions -r)
 
175
PY3DEFAULT := $(shell py3versions -d)
 
176
PYTHON3 := $(filter-out $(PY3DEFAULT),$(PY3REQUESTED)) python3
 
177
 
 
178
override_dh_auto_clean:
 
179
        -rm -rf build
 
180
 
 
181
override_dh_auto_build:
 
182
        set -ex; for python in $(PYTHON3); do \\
 
183
            $$python setup.py build; \\
 
184
        done
 
185
 
 
186
override_dh_auto_install:
 
187
        set -ex; for python in $(PYTHON3); do \\
 
188
            $$python setup.py install \\
 
189
                --root=''' + build_dir + '''\\
 
190
                --install-layout=deb; \\
 
191
        done
 
192
'''
 
193
    msg += '\n# Customize by adding override scripts\n'
 
194
    ###################################################################
 
195
    # write to file
 
196
    ###################################################################
 
197
    writefile(para, 'debian/rules', msg)
 
198
    return
 
199
 
 
200
#######################################################################
 
201
def README_Debian(para):
 
202
    sep = '-' * (len(para['package']) + 11)
 
203
    msg = '''\
 
204
{0} for Debian
 
205
{1}
 
206
 
 
207
Please edit this to provide information specific information on 
 
208
this {0} Debian package.
 
209
 
 
210
    (Automatically generated by {2} Version {3})
 
211
 
 
212
 -- {4} <{5}>  {6}
 
213
'''.format(
 
214
            para['package'], 
 
215
            sep, 
 
216
            para['program_name'], 
 
217
            para['program_version'], 
 
218
            para['fullname'], 
 
219
            para['email'], 
 
220
            para['date'])
 
221
    ###################################################################
 
222
    # write to file
 
223
    writefile(para, 'debian/README.Debian', msg)
 
224
    return
 
225
 
 
226
#######################################################################
 
227
def changelog(para):
 
228
    if para['native']:
 
229
        msg = '''\
 
230
{0} ({1}) UNRELEASED; urgency=low
 
231
 
 
232
  * Initial release. Closes: #nnnn
 
233
    <nnnn is the bug number of your ITP>
 
234
 
 
235
 -- {2} <{3}>  {4}
 
236
'''.format(
 
237
            para['package'], 
 
238
            para['version'], 
 
239
            para['fullname'], 
 
240
            para['email'],
 
241
            para['date'])
 
242
    else:
 
243
        msg = '''\
 
244
{0} ({1}-{2}) UNRELEASED; urgency=low
 
245
 
 
246
  * Initial release. Closes: #nnnn
 
247
    <nnnn is the bug number of your ITP>
 
248
 
 
249
 -- {3} <{4}>  {5}
 
250
'''.format(
 
251
            para['package'], 
 
252
            para['version'], 
 
253
            para['revision'], 
 
254
            para['fullname'], 
 
255
            para['email'],
 
256
            para['date'])
 
257
    ###################################################################
 
258
    # write to file
 
259
    writefile(para, 'debian/changelog', msg)
 
260
 
 
261
#######################################################################
 
262
def control(para):
 
263
    file = 'debian/control'
 
264
    if not para['overwrite'] and os.path.isfile(file) and os.stat(file).st_size != 0:
 
265
        print('I: File already exits, skipping: {}'.format(file), file=sys.stderr)
 
266
        return
 
267
    else:
 
268
        msg = control_src(para)
 
269
        for deb in para['debs']:
 
270
            msg += control_bin(para, deb)
 
271
        writefile(para, 'debian/control', msg)
 
272
        return
 
273
 
 
274
#######################################################################
 
275
def control_src(para):
 
276
    msg = '''\
 
277
Source: {0}
 
278
Section: {1}
 
279
Priority: {2}
 
280
Maintainer: {3} <{4}>
 
281
Build-Depends: {5}
 
282
Standards-Version: {6}
 
283
Homepage: {7}
 
284
{8}: {9}
 
285
{10}: {11}
 
286
'''.format(
 
287
            para['package'],
 
288
            para['section'],
 
289
            para['priority'],
 
290
            para['fullname'],
 
291
            para['email'], 
 
292
            ',\n\t'.join(para['build_depends']),
 
293
            para['standard_version'],
 
294
            para['homepage'],
 
295
            guess_vcsvcs(para['vcsvcs']),
 
296
            para['vcsvcs'],
 
297
            guess_vcsbrowser(para['vcsbrowser']),
 
298
            para['vcsbrowser'])
 
299
    if 'python2' in para['dh_with']:
 
300
        msg += 'X-Python-Version: >= 2.6\n'
 
301
    if 'python3' in para['dh_with']:
 
302
        msg += 'X-Python3-Version: >= 3.2\n'
 
303
    # anythong for perl and others XXX FIXME XXX
 
304
    msg += '\n'
 
305
    ###################################################################
 
306
    return msg
 
307
 
 
308
#######################################################################
 
309
def guess_vcsvcs(vcsvcs):
 
310
    if re.search('\.git$', vcsvcs):
 
311
        return 'Vcs-Git'
 
312
    elif re.search('\.hg$', vcsvcs):
 
313
        return 'Vcs-Hg'
 
314
    elif re.search('^:pserver:', vcsvcs):
 
315
        # CVS :pserver:anonymous@anonscm.debian.org:/cvs/webwml
 
316
        return 'Vcs-Cvs'
 
317
    elif re.search('^:ext:', vcsvcs):
 
318
        # CVS :ext:username@cvs.debian.org:/cvs/webwml
 
319
        return 'Vcs-Cvs'
 
320
    elif re.search('^svn[:+]', vcsvcs):
 
321
        # SVN svn://svn.debian.org/ddp/manuals/trunk manuals
 
322
        # SVN svn+ssh://svn.debian.org/svn/ddp/manuals/trunk
 
323
        return 'Vcs-Svn'
 
324
    else:
 
325
        return '#Vcs-Git'
 
326
 
 
327
#######################################################################
 
328
def guess_vcsbrowser(vcsbrowser):
 
329
    if re.search('\.git$', vcsbrowser):
 
330
        return 'Vcs-Browser'
 
331
    elif re.search('\.hg$', vcsbrowser):
 
332
        return 'Vcs-Browser'
 
333
    elif re.search('^:pserver:', vcsbrowser):
 
334
        # CVS :pserver:anonymous@anonscm.debian.org:/cvs/webwml
 
335
        return 'Vcs-Browser'
 
336
    elif re.search('^:ext:', vcsbrowser):
 
337
        # CVS :ext:username@cvs.debian.org:/cvs/webwml
 
338
        return 'Vcs-Browser'
 
339
    elif re.search('^svn[:+]', vcsbrowser):
 
340
        # SVN svn://svn.debian.org/ddp/manuals/trunk manuals
 
341
        # SVN svn+ssh://svn.debian.org/svn/ddp/manuals/trunk
 
342
        return 'Vcs-Browser'
 
343
    else:
 
344
        return '#Vcs-Browser'
 
345
 
 
346
#######################################################################
 
347
def control_bin(para, deb):
 
348
    if para['monoarch']:
 
349
        msg = '''\
 
350
Package: {0}
 
351
Architecture: {1}
 
352
Depends: {2}
 
353
Description: {3}
 
354
{4}
 
355
'''.format(
 
356
            deb['package'],
 
357
            deb['arch'],
 
358
            ',\n\t'.join(deb['depends']),
 
359
            deb['desc'],
 
360
            deb['desc_long'])
 
361
    else:
 
362
        msg = '''\
 
363
Package: {0}
 
364
Architecture: {1}
 
365
Multi-Arch: {2}
 
366
Pre-Depends: {3}
 
367
Depends: {4}
 
368
Description: {5}
 
369
{6}
 
370
'''.format(
 
371
            deb['package'],
 
372
            deb['arch'],
 
373
            deb['multiarch'],
 
374
            ',\n\t'.join(deb['pre-depends']),
 
375
            ',\n\t'.join(deb['depends']),
 
376
            deb['desc'],
 
377
            deb['desc_long'])
 
378
    return msg
 
379
 
 
380
#######################################################################
 
381
 
 
382
###################################################################
 
383
# Write copyright and license
 
384
#  using writefile(para, file, text, append=False)
 
385
###################################################################
 
386
def copyright(para):
 
387
    if not para['overwrite'] and os.path.isfile('debian/copyright') and os.stat('debian/copyright').st_size != 0:
 
388
        print('I: File already exits, skipping: {}'.format('debian/copyright'), file=sys.stderr)
 
389
        return
 
390
    # get scan result of copyright
 
391
    (bdata, nonlink_files, binary_files, huge_files) = debmake.copyright.scan_copyright_data()
 
392
    # make text to print
 
393
    text = '''\
 
394
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 
395
Upstream-Name: {}
 
396
Source: <url://example.com>
 
397
 
 
398
'''.format(para['package'])
 
399
    for bd in bdata:
 
400
        text += '#----------------------------------------------------------------------------\n'
 
401
        text += 'Files: {}\n'.format('\n\t'.join(bd[1]))
 
402
        # Copyright:
 
403
        text += 'Copyright:'
 
404
        for name in bd[2].keys():
 
405
            # name found
 
406
            if bd[2][name][0] == bd[2][name][1]:
 
407
                if bd[2][name][1] == 0: # max == 0 for binary etc.
 
408
                    text += ' {}\n'.format(name)    # XXXXX FIXME
 
409
                else:
 
410
                    text += ' {} {}\n'.format(bd[2][name][0], name)
 
411
            else:
 
412
                if bd[2][name][1] == 0: # max == 0 means not found
 
413
                    text += ' {}\n'.format(name)
 
414
                else:
 
415
                    text += ' {}-{} {}\n'.format(bd[2][name][0], bd[2][name][1], name)
 
416
        if bd[3] == []:
 
417
            text += 'License: NO_LICENSE_TEXT_FOUND\n\n'
 
418
        else:
 
419
            text += 'License:\n {}\n'.format(debmake.copyright.format_license(bd[3]))
 
420
        # add comments
 
421
        if bd[4] != '':
 
422
            text += '#............................................................................\n'
 
423
            text += '# Gray hits with matching text of "copyright":\n'
 
424
            text += bd[4]
 
425
    if binary_files != []:
 
426
        text += '#----------------------------------------------------------------------------\n'
 
427
        text += '# Binary files (skipped):\n# {}\n\n'.format('\n# '.join(binary_files))
 
428
    if huge_files != []:
 
429
        text += '#----------------------------------------------------------------------------\n'
 
430
        text += '# Huge files   (skipped):\n# {}\n\n'.format('\n# '.join(huge_files))
 
431
    text += '''\
 
432
#----------------------------------------------------------------------------
 
433
# This is meant only as a template example.
 
434
#
 
435
# Edit this accordinng to the "Machine-readable debian/copyright file" as
 
436
# http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ .
 
437
#
 
438
# Generate typical license templates with the "debmake -x" and merge them 
 
439
# into here as needed.  See "man 8 debmake" for more.
 
440
#
 
441
# Please avoid to pick license terms that are more restrictive than the
 
442
# packaged work, as it may make Debian's contributions unacceptable upstream.
 
443
 
 
444
'''
 
445
    for f in debmake.copyright.license_files(para):
 
446
        text += '#----------------------------------------------------------------------------\n'
 
447
        text += '# License: {}\n'.format(f)
 
448
        text += debmake.copyright.license_text(f)
 
449
        text += '\n'
 
450
 
 
451
    writefile(para, 'debian/copyright', text)
 
452
    return
 
453
 
 
454
#######################################################################
 
455
def extra(para):
 
456
    for file in glob.glob(para['base_path'] + '/share/debmake/extra/*'):
 
457
        with open(file, 'r') as f:
 
458
            text = f.read()
 
459
        writefile(para, 
 
460
            'debian/' + os.path.basename(file), 
 
461
            subst(para, text))
 
462
    return
 
463
 
 
464
#######################################################################
 
465
#debs =[{'package': p,
 
466
#        'arch': a,
 
467
#        'type': t,
 
468
#        'multiarch': m,
 
469
#        'desc': desc,
 
470
#        'desc_long': desc_long,
 
471
#        'depends': dp,
 
472
#        'pre-depends': pd}, ...}
 
473
#######################################################################
 
474
def install(para):
 
475
    #text = '# see dh_install'
 
476
    for deb in para['debs']:
 
477
        if deb['type'] == 'lib':
 
478
            text = 'lib/\nusr/lib/\n'
 
479
        elif deb['type'] == 'bin' or deb['type'] == 'script':
 
480
            text = 'bin/\nusr/bin/\nsbin/\nusr/sbin/\n'
 
481
        elif deb['type'] == 'data':
 
482
            text = 'usr/share/' + para['package'] + '/\n'
 
483
        else:
 
484
            text = ''
 
485
        writefile(para, 
 
486
            'debian/' + deb['package'] +'.install', 
 
487
            text)
 
488
    return
 
489
 
 
490
#######################################################################
 
491
def installdocs(para):
 
492
    #text = '# see dh_install'
 
493
    for deb in para['debs']:
 
494
        if deb['type'] == 'doc':
 
495
            text = 'usr/share/doc/' + deb['package'] + '/\n'
 
496
            writefile(para, 
 
497
                'debian/' + deb['package'] +'.docs', 
 
498
                text)
 
499
    return
 
500
 
 
501
#######################################################################
 
502
def docbase(para):
 
503
    for deb in para['debs']:
 
504
        if deb['type'] == 'doc':
 
505
            text = '''\
 
506
Document: {0}
 
507
Title: Debian {1} Manual
 
508
Author: <insert document author here>
 
509
Abstract: This manual describes what {1} is
 
510
 and how it can be used to
 
511
 manage online manuals on Debian systems.
 
512
Section: unknown
 
513
 
 
514
Format: PDF
 
515
Files: /usr/share/doc/{0}/{1}.pdf.gz
 
516
 
 
517
Format: text
 
518
Files: /usr/share/doc/{0}/{1}.text.gz
 
519
 
 
520
Format: HTML
 
521
Index: /usr/share/doc/{0}/html/index.html
 
522
Files: /usr/share/doc/{0}/html/*.html
 
523
'''.format(deb['package'], para['package'])
 
524
            writefile(para, 
 
525
                'debian/' + deb['package'] +'.doc-base', 
 
526
                text)
 
527
    return
 
528
 
 
529
#######################################################################
 
530
def manpages(para):
 
531
    for deb in para['debs']:
 
532
        if deb['type'] == 'bin':
 
533
            text = '# See dh_installman(1)\n'
 
534
            writefile(para, 
 
535
                'debian/' + deb['package'] +'.manpages', 
 
536
                text)
 
537
    return
 
538
 
 
539
#######################################################################
 
540
# Test script
 
541
#######################################################################
 
542
if __name__ == '__main__':
 
543
    para = {}
 
544
    para['package'] = 'package'
 
545
    para['year'] = '9999'
 
546
    para['fullname'] = 'fullname'
 
547
    para['email'] = 'foo@example.org'
 
548
    para['shortdate'] = '1919-12-19'
 
549
    text = '@PACKAGE@ @UCPACKAGE@ @YEAR@ @USERNAME@ @EMAIL@ @SHORTDATE@'
 
550
    print(subst(para, text))
 
551