/[ascend]/trunk/tools/dtar/dtar
ViewVC logotype

Contents of /trunk/tools/dtar/dtar

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2126 - (show annotations) (download)
Thu Dec 17 01:05:08 2009 UTC (10 years, 9 months ago) by jpye
File size: 10055 byte(s)
Add 'debhelper' as required dependency.
Use shutil to move files into home dir (for case where /tmp is on different volume).
1 #!/usr/bin/env python
2 # dtar - Tool to produce .deb package from source tarball
3 # Copyright (C) 2008 John Pye <john@curioussymbols.com>
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2, or (at your option)
8 # any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330,
18 # Boston, MA 02111-1307, USA.
19
20 import sys, re, tarfile, os.path, subprocess, shutil, getopt, glob
21 import apt
22 from debian_bundle import deb822, changelog
23
24 def usage():
25 print """%s: create debian package directly from source code tarball
26 %s [-s] originaltarball.tar.* [debian.tar.bz2|debian.tar.gz]
27
28 originaltarball.tar.*
29 The tarball containing the source code for the package
30 or packages you are going to create
31 debian.tar.*
32 OPTIONAL tarball containing the debian files
33 for your package. Only use this file if you have excluded
34 the debian/* files from your original source code tarball.
35 It is probably best to use a separate debian* tarball
36 for these files if you are likely to run into build
37 problems, eg when uploading packages to a build farm such
38 as Ubuntu PPA or openSUSE Build Service.
39
40 -s
41 --source Create source package only, no binary
42
43 -h
44 -help Print this message.
45
46 -n
47 --nooverwrite
48 Do not overwrite package files in current directory at
49 the end of the build.
50
51 -k
52 --keep
53 Keep temporary files at end of build, for checking/debugging
54 purposes. These will be in /tmp/dtar-*, and you will have to
55 manually delete them yourself if you use this option. Normally
56 all the files are deleted if the build completes successfully.
57 """
58
59 opts,args = getopt.getopt(sys.argv[1:],"nhsk",["help","source","nooverwrite","keep"])
60
61 # do we just want a source package?
62 buildsource = False
63 overwrite = True
64 clean = True
65
66 for _o,_a in opts:
67 if _o in ['-h','--help']:
68 usage()
69 sys.exit()
70 elif _o in ['-s','--source']:
71 buildsource = True
72 elif _o in ['-n','--nooverwrite']:
73 overwrite = False
74 elif _o in ['-k','--keep']:
75 clean = False
76 else:
77 assert False,"unhandled option"
78
79 if len(args)<1 or len(args)>2:
80 raise RuntimeError("One or two tarballs must be supplied to dtar! (see dtar --help)")
81
82 # the tarball is the argument to this script
83
84 startingcwd = os.getcwd()
85
86 f = args[0]
87
88 fmeta = None
89 if len(args)==2:
90 # debian.tar.* meta-file tarball, optional
91 fmeta = args[1]
92 fmetafull = os.path.abspath(fmeta)
93
94 if not os.path.exists(fmeta):
95 raise RuntimeError("Debian metadata tarball '%s' was not found" % fmeta)
96
97 ffull = os.path.abspath(f)
98
99 # get the first filename in the tarball
100 t = tarfile.open(ffull)
101 M = t.getmembers()
102 print M[0].name
103
104 # split the top-level directory name from that path
105
106 for i in [0,1]:
107 print "name =",M[i].name
108 h,path = os.path.split(M[i].name)
109 print "h =",h
110 print "path =",path
111 if h:
112 break
113 if not h:
114 raise RuntimeError("Tarball appears not contain a top-level directory")
115
116 while h:
117 head = h
118 h,path = os.path.split(path)
119
120 print "Head directory = ",head
121
122 r = re.compile(r"^%s/debian/([^/]*)$" % re.escape(head))
123 r2 = re.compile(r"^debian/([^/]*)$")
124
125 debfiles = {}
126 # this is a dictionary of sequences, first element 'm' or 's' depending
127 # on whether the debian file comes from the 'meta' tarball (if given), or the
128 # source tarball.
129
130 # search for debian/* files inside the original tarball
131
132 for m in M:
133 if r.match(m.name):
134 h,p = os.path.split(m.name)
135 debfiles[p] = [t,m]
136
137 # search for debian/* files inside the meta tarball
138 tmeta = None
139 if fmeta:
140 tmeta = tarfile.open(fmetafull)
141 Mmeta = tmeta.getmembers()
142 for m in Mmeta:
143 print "meta file contains '%s'" % m.name
144 if r2.match(m.name):
145 h,p = os.path.split(m.name)
146 debfiles[p] = [tmeta,m]
147
148 def getdebfile(name):
149 _t,_f = debfiles[name]
150 return _t.extractfile(_f)
151
152 mandatorydebfiles = ['control','changelog','rules']
153
154 missingdebfiles = []
155 for _f in mandatorydebfiles:
156 if _f not in debfiles:
157 missingdebfiles.append(_f)
158 if missingdebfiles:
159 s = "Tarball(s) missing required debian/* files: %s" %missingdebfiles
160 raise RuntimeError(s)
161
162 fc = getdebfile('control')
163
164 # display mandatory fields from 'debian/control'
165
166 controlmandatory = ['Source','Maintainer']
167
168 control = deb822.Deb822(fc.read())
169 for _c in controlmandatory:
170 print "%s: %s" % (_c, control[_c])
171
172 # check that debian/changelog is current
173
174 fchange = getdebfile('changelog')
175
176 changes = changelog.Changelog(file=fchange.read())
177
178 debianname = "%s-%s" % (control['Source'],changes.upstream_version)
179
180 need_tarball_reheaded = False
181 if debianname != head:
182 need_tarball_reheaded = True
183 #raise RuntimeError("Debian files not up to date: debian/changelog refers to version '%s' but tarball head directory is '%s'"
184 # % (debianname,head));
185
186 # check for build-time dependencies
187
188 dependencies = ['build-essential','fakeroot','debhelper']
189
190 if 'Build-Depends' in control:
191 #print "Build-Depends:",control['Build-Depends']
192 c = apt.Cache()
193 dependencies += control['Build-Depends'].split(', ')
194
195 print "Checking build dependencies..."
196 depsmissing = []
197 for d in dependencies:
198 if d not in c or not c[d].isInstalled:
199 depsmissing.append(d)
200
201 if depsmissing:
202 raise RuntimeError("Unable to proceed. Missing buildtime dependencies: %s" % (depsmissing))
203
204 # extract tarball to tmp dir
205
206 maindir = "/tmp/dtar-%s" % os.getpid()
207
208 if os.path.exists(maindir):
209 raise RuntimeError("Temp path '%s' already exists!"%maindir)
210
211 os.mkdir(maindir)
212
213 try:
214 # extract source code tarball
215
216 print "Extracting tarball to '%s'..." % maindir
217 os.chdir(maindir)
218 t.extractall()
219 assert(os.path.exists(head))
220 print "Files extracted to '%s'" % os.getcwd()
221
222 # extract meta-file tarball if provided
223
224 if tmeta:
225 print "Extracting meta tarball to '%s'..." % maindir
226 os.chdir(os.path.join(maindir,head))
227 tmeta.extractall()
228 os.chdir(maindir)
229
230 assert(os.path.exists(os.path.join(head,"debian/control")))
231
232 # copy original tarball (recompressing to .gz/reheading if required?)
233
234 unzip = None
235 ext = None
236 if f[-7:] == ".tar.gz" or f[-4:] == ".tgz":
237 print "Original tarball is in gzip format"
238 unzip = ["gzip","-d"]
239 exe = "/bin/gzip"
240 ext = "gz"
241 elif f[-8:] == ".tar.bz2":
242 print "Original tarball is in bzip2 format"
243 unzip = ["bzip2","-d"]
244 exe = "/bin/bzip2"
245 ext = "bz2"
246
247 if not unzip:
248 raise RuntimeError("Unrecognised input format for '%s'" % f)
249
250 if need_tarball_reheaded:
251 print "Extracting tarball for re-heading..."
252 tar1 = tarfile.open(ffull)
253 tar1.extractall()
254 tar1.close()
255 print "Renaming head directory from '%s' to '%s'..." % (head,debianname)
256 assert(os.path.exists(head))
257 os.rename(head,debianname)
258 assert(os.path.exists(debianname))
259 print "Re-zipping in .tar.gz format..."
260 temptar = "%s_%s.orig.tar" % (control['Source'],changes.upstream_version)
261 temptz = "%s.%s"%(temptar,ext)
262 tar = tarfile.open(temptz, "w:gz")
263 tar.add(debianname, recursive=True)
264 tar.close()
265 assert(os.path.exists(temptz))
266
267 elif ext != "gz":
268 print "Source tarball needs to be re-zipped to gzip format."
269 temptar = "%s_%s.orig.tar" % (control['Source'],changes.upstream_version)
270 temptz = "%s.%s"%(temptar,ext)
271 print "Creating tarball copy '%s'" % temptz
272 shutil.copyfile(ffull,temptz)
273 print "Extracting with %s..." % unzip[0]
274 subprocess.call(unzip + [temptz], executable=exe)
275 assert(os.path.exists(temptar))
276 print "Recompressing with gzip..."
277 subprocess.call(['gzip',temptar])
278
279 else:
280 origname = "%s_%s.orig.tar.gz" % (control['Source'],changes.upstream_version)
281 print "Original tarball is in gzip format"
282 shutil.copyfile(ffull, origname)
283
284 print "Checking for correct original tarball name..."
285 origname = "%s_%s.orig.tar.gz" % (control['Source'],changes.upstream_version)
286 assert(os.path.exists(origname))
287
288 t1 = t
289
290 # build the source package
291 #print "Building source package..."
292 #res = subprocess.call(["dpkg-source","-b",head,ffull],executable="/usr/bin/dpkg-source")
293
294 #if res:
295 # raise RuntimeError("dpkg-source returned error code %d" % res)
296
297 # build the binary package
298 print "Entering directory '%s'" % debianname
299 os.chdir(debianname)
300 if buildsource:
301 print "Building source package..."
302 res = subprocess.call(["debuild","-rfakeroot","-S","-sa"])
303 else:
304 print "Building binary package..."
305 res = subprocess.call(["dpkg-buildpackage","-rfakeroot","-sa"])
306
307 if res:
308 raise RuntimeError("dpkg-buildpackage returned error code %s" % res)
309
310 except Exception, e:
311 print "ERROR DURING DPKG-BUILDPACKAGE: %s"% str(e)
312 print "Temporary files can be inspected in %s" % maindir
313 sys.exit(1)
314
315 print "Found files:"
316 os.chdir(maindir)
317 resultfiles = glob.glob("*.dsc") + glob.glob("*.deb") + glob.glob("*.gz") + glob.glob("*.changes")
318 print resultfiles
319
320 # move found files to current directory
321 failedtomovefiles = []
322 for _f in resultfiles:
323 _p2 = os.path.join(startingcwd,_f)
324
325 if not overwrite and os.path.exists(_p2):
326 failedtomovefiles.append(_f)
327 shutil.move(_f, _p2)
328
329 if failedtomovefiles:
330 raise RuntimeError("Failed to move the following files (check --nooverwrite): %s",failedtomovefiles)
331
332 #clean up files
333
334 if clean:
335 print "Cleaning up files from '%s'..." % maindir
336 assert maindir[:10]=="/tmp/dtar-"
337 for _root,_dirs,_files in os.walk(maindir,topdown=False):
338 for _f in _files:
339 os.remove(os.path.join(_root,_f))
340 for _d in _dirs:
341 os.rmdir(os.path.join(_root,_d))
342 os.rmdir(maindir)
343 else:
344 print "Leaving all temporary files in '%s'..." % maindir
345
346 print "All done, exiting"

Properties

Name Value
svn:executable *

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22