Added initial code
[qice] / bdist_debian.py
1 # bdist_debian.py
2 #
3 # Add 'bdist_debian' Debian binary package distribution support to 'distutils'.
4 #
5 # This command builds '.deb' packages and supports the "Maemo" extensions for the Nokia N770/N800/N810.
6 #
7 # Written by: Gene Cash <gene.cash@gmail.com> 16-NOV-2007
8
9 import os, base64
10 from distutils.core import Command, Distribution
11 from distutils.dir_util import remove_tree
12 from distutils.util import byte_compile
13
14 # make these legal keywords for setup()
15 Distribution.icon=None
16 Distribution.section=None
17 Distribution.depends=None
18
19 class ControlFile(object):
20     def __init__(self, Installed_Size=0, Long_Description='', Description='', Icon='', **kwargs):
21         self.options=kwargs
22         self.description=Description
23         self.long_description=Long_Description
24         self.icon=Icon
25         self.installed_size=Installed_Size
26
27     def getContent(self):
28         content=['%s: %s' % (k, v) for k,v in self.options.iteritems()]
29
30         content.append('Installed-Size: %d' % self.installed_size)
31         if self.description != 'UNKNOWN':
32             content.append('Description: %s' % self.description.strip())
33             if self.long_description != 'UNKNOWN':
34                 self.long_description=self.long_description.replace('\n', '\n ')
35                 content.append(' '+self.long_description.strip())
36
37         if self.icon:
38             # generate Base64-encoded icon
39             s=file(self.icon, 'rb').read()
40             x=base64.b64encode(s)
41             # wrap width MUST be 76 characters to make application manager happy after install
42             lw=76
43             # trailing blank is important, and the XB- is NOT legal
44             content.append('XB-Maemo-Icon-26: ')
45             for i in range(0, len(x), lw):
46                 content.append(' '+x[i:i+lw])
47
48         # must have two returns
49         return '\n'.join(content)+'\n\n'
50
51 class bdist_debian(Command):
52     description=''
53     # List of option tuples: long name, short name (None if no short name), and help string.
54     user_options=[('name=', None, 'Package name'),
55                   ('section=', None, 'Section (Only "user/*" will display in App Mgr usually)'),
56                   ('priority=', None, 'Priority'),
57                   ('depends=', None, 'Other Debian package dependencies (comma separated)'),
58                   ('icon=', None, 'Name of icon file to be displayed by App Mgr')]
59
60     def initialize_options(self):
61         self.section=None
62         self.priority=None
63         self.depends=None
64         self.icon=None
65
66     def finalize_options(self):
67         if self.section is None:
68             self.section='user/other'
69
70         if self.priority is None:
71             self.priority='optional'
72
73         self.maintainer='%s <%s>' % (self.distribution.get_maintainer(), self.distribution.get_maintainer_email())
74
75         if self.depends is None:
76             self.depends='python2.5'
77
78         self.name=self.distribution.get_name()
79         self.description=self.distribution.get_description()
80         self.long_description=self.distribution.get_long_description()
81         self.version=self.distribution.get_version()
82
83         # process new keywords
84         if self.distribution.icon != None:
85             self.icon=self.distribution.icon
86         if self.distribution.section != None:
87             self.section=self.distribution.section
88         if self.distribution.depends != None:
89             self.depends=self.distribution.depends
90
91     def run(self):
92         build_dir=os.path.join(self.get_finalized_command('build').build_base, 'nokia')
93         dist_dir='dist'
94         binary_fn='debian-binary'
95         control_fn='control'
96         data_fn='data'
97         tgz_ext='.tar.gz'
98
99         # build everything locally
100         self.run_command('build')
101         install=self.reinitialize_command('install', reinit_subcommands=1)
102         install.root=build_dir
103         self.run_command('install')
104
105         # find out how much space it takes
106         installed_size=0
107         for root, dirs, files in os.walk('build'):
108             installed_size+=sum(os.path.getsize(os.path.join(root, name)) for name in files)
109
110         # make compressed tarball
111         self.make_archive(os.path.join(dist_dir, data_fn), 'gztar', root_dir=build_dir)
112
113         # remove all the stuff we just built
114         remove_tree(build_dir)
115
116         # create control file contents
117         ctl=ControlFile(Package=self.name, Version=self.version, Section=self.section, Priority=self.priority,
118                         Installed_Size=installed_size/1024+1, Architecture='all', Maintainer=self.maintainer,
119                         Depends=self.depends, Description=self.description, Long_Description=self.long_description,
120                         Icon=self.icon).getContent()
121
122         # grab scripts
123         scripts={}
124         for fn in ('postinst', 'preinst', 'postrm', 'prerm', 'config'):
125             if os.path.exists(fn):
126                 scripts[fn]=file(fn, 'rb').read()
127
128         # now to create the deb package
129         os.chdir(dist_dir)
130
131         # write control file
132         file(control_fn, 'wb').write(ctl)
133
134         # write any scripts and chmod a+rx them
135         files=[control_fn]
136         for fn in scripts:
137             files.append(fn)
138             file(fn, 'wb').write(scripts[fn])
139             os.chmod(fn, 0555)
140
141         # make "control" compressed tarball with control file and any scripts
142         self.spawn(['tar', '-czf', control_fn+tgz_ext]+files)
143
144         # make debian-binary file
145         file(binary_fn, 'wb').write('2.0\n')
146
147         # make final archive
148         package_filename='%s_%s_all.deb' % (self.name, self.version)
149         self.spawn(['ar', '-cr', package_filename, binary_fn, control_fn+tgz_ext, data_fn+tgz_ext])