Release 14.0.1-2
[pkg-mozilla/iceweasel.git] / debian / repack.py
1 #!/usr/bin/python
2
3 from optparse import OptionParser
4 import fnmatch
5 import tarfile
6 import StringIO
7 import re
8 import os
9 import sys
10 import rfc822
11 import urllib2
12 from urlparse import urlparse
13
14 class URLFile(object):
15     '''Simple proxy to urllib2.urlopen, that responds to seek only if
16        it's called before read. This is enough for tarfile to be happy'''
17
18     def __init__(self, url):
19         self.file = urllib2.urlopen(url)
20
21     def seek(self, offset, whence = os.SEEK_SET):
22         if whence != os.SEEK_SET or offset != 0 or self.read == self._read:
23             raise "unsupported"
24
25     def _read(self, size = -1):
26         return self.file.read(size)
27
28     def read(self, size = -1):
29         self.read = self._read
30         return self._read(size)
31
32     def close(self):
33         self.file.close()
34
35 def dirname(filespec):
36     '''Returns os.path.dirname if a file, and '' if an url'''
37     if urlparse(filespec).scheme:
38         return ''
39     return os.path.dirname(filespec)
40
41 class TarFilterList(object):
42     def __init__(self, filename):
43         self.patterns = {}
44         for filt in open(filename).readlines():
45             f = filt.strip().split(None, 1)
46             if len(f) == 1:
47                 [pat] = f
48                 cmd = None
49             else:
50                 [pat, cmd] = f
51
52             pat = pat.split(os.sep)
53             self.add_pattern(pat, self.patterns, cmd)
54
55     def add_pattern(self, pat, patterns, cmd):
56         if re.search(r'[\[\?\*]', pat[0]):
57             if not '*' in patterns:
58                 patterns['*'] = []
59             patterns['*'].append([os.sep.join(pat), cmd, False])
60         else:
61             if not pat[0] in patterns:
62                 patterns[pat[0]] = {}
63             if len(pat) > 2:
64                 self.add_pattern(pat[1:], patterns[pat[0]], cmd)
65             else:
66                 if not '*' in patterns[pat[0]]:
67                     patterns[pat[0]]['*'] = []
68                 patterns[pat[0]]['*'].append([os.sep.join(pat[1:]), cmd, False])
69
70     def match(self, name):
71         name = name.split(os.sep)[1:]
72         if len(name) == 0:
73             return False
74         return self._match(name, self.patterns)
75
76     def _match(self, name, patterns):
77         if len(name) > 1 and name[0] in patterns:
78             cmd = self._match(name[1:], patterns[name[0]])
79             if cmd != False:
80                 return cmd
81         if '*' in patterns:
82             for pat in patterns['*']:
83                 if fnmatch.fnmatch(name[0], pat[0]) or fnmatch.fnmatch(os.sep.join(name), pat[0]):
84                     pat[2] = True
85                     return pat[1]
86         return False
87
88     def unused(self, patterns=None, root=''):
89         result = []
90         if root:
91             root += '/'
92         if not patterns:
93             patterns = self.patterns
94         for pat in patterns:
95             if pat != '*':
96                 result += self.unused(patterns[pat], root + pat)
97             else:
98                 for p in patterns[pat]:
99                     if not p[2]:
100                         result.append(root + p[0])
101         return result
102
103 def file_extension(name):
104     return os.path.splitext(name)[1][1:]
105
106 def filter_tar(orig, new, filt, topdir = None):
107     filt = TarFilterList(filt)
108     if urlparse(orig).scheme:
109         tar = tarfile.open(orig, "r:" + file_extension(orig), URLFile(orig))
110     else:
111         tar = tarfile.open(orig, "r:" + file_extension(orig))
112     new_tar = tarfile.open(new + ".new", "w:" + file_extension(new))
113
114     while True:
115         info = tar.next()
116         if not info:
117             break
118         if topdir:
119             info.name = "/".join([topdir] + info.name.split("/")[1:])
120         do_filt = filt.match(info.name)
121         if do_filt == None:
122             print >> sys.stderr, "Removing %s" % (info.name)
123             continue
124
125         if info.isfile():
126             file = tar.extractfile(info)
127             if do_filt:
128                 print >> sys.stderr, "Filtering %s" % (info.name)
129                 orig = file
130                 file = StringIO.StringIO()
131                 the_filt = lambda l: l
132                 if do_filt[0].isalpha():
133                     f = do_filt.split(do_filt[1])
134                     if f[0] == 's':
135                         the_filt = lambda l: re.sub(f[1], f[2], l)
136                 else:
137                     f = do_filt.split(do_filt[0])
138                     if f[2] == 'd':
139                         the_filt = lambda l: "" if re.search(f[1], l) else l
140                 file.writelines(map(the_filt, orig.readlines()))
141                 file.seek(0);
142                 info.size = len(file.buf)
143             new_tar.addfile(info, file)
144         else:
145             new_tar.addfile(info)
146
147     tar.close()
148     new_tar.close()
149     os.rename(new_tar.name, new)
150     unused = filt.unused()
151     if unused:
152         print 'Unused filters:'
153         print '', '\n '.join(unused)
154         exit(1)
155
156 def get_package_name():
157     control = os.path.join(os.path.dirname(__file__), "control")
158     return rfc822.Message(open(control))["Source"]
159
160 def main():
161     parser = OptionParser()
162     parser.add_option("-u", "--upstream-version", dest="upstream_version",
163         help="define upstream version number to use when creating the file",
164         metavar="VERSION")
165     parser.add_option("-f", "--filter", dest="filter",
166         help="use the given filter list", metavar="FILE")
167     parser.add_option("-p", "--package", dest="package",
168         help="use the given package name", metavar="NAME")
169     parser.add_option("-o", "--output", dest="new_file",
170         help="save the filtered tarball as the given file name", metavar="FILE")
171     parser.add_option("-t", "--topdir", dest="topdir",
172         help="replace the top directory with the given name", metavar="NAME")
173     (options, args) = parser.parse_args()
174
175     if not options.upstream_version and not options.new_file:
176         parser.error("Need an upstream version")
177         return
178
179     if len(args) < 1:
180         parser.error("Too few arguments")
181         return
182     if len(args) > 1:
183         parser.error("Too many arguments")
184         return
185
186     if not options.filter:
187         options.filter = os.path.join(os.path.dirname(__file__), "source.filter")
188     if not options.package:
189         options.package = get_package_name()
190
191     if options.new_file:
192         new_file = options.new_file
193
194     if os.path.islink(args[0]):
195         orig = os.path.realpath(args[0])
196         if not new_file:
197             new_file = args[0]
198     else:
199         orig = args[0]
200         compression = file_extension(orig)
201         if not new_file:
202             new_file = options.package + "_" + options.upstream_version + ".orig.tar." + compression
203             new_file = os.path.realpath(os.path.join(dirname(orig), new_file))
204     print orig, new_file
205     filter_tar(orig, new_file, options.filter, options.topdir)
206
207 if __name__ == '__main__':
208     main()