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

Annotation of /trunk/tools/dtar/dtar

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2126 - (hide 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 jpye 1815 #!/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 jpye 1820 import sys, re, tarfile, os.path, subprocess, shutil, getopt, glob
21 jpye 1815 import apt
22     from debian_bundle import deb822, changelog
23    
24 jpye 1820 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 jpye 2089 -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 jpye 1820 """
58    
59 jpye 2089 opts,args = getopt.getopt(sys.argv[1:],"nhsk",["help","source","nooverwrite","keep"])
60 jpye 1820
61     # do we just want a source package?
62     buildsource = False
63     overwrite = True
64 jpye 2089 clean = True
65 jpye 1820
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 jpye 2089 elif _o in ['-k','--keep']:
75     clean = False
76 jpye 1820 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 jpye 1815 # the tarball is the argument to this script
83    
84 jpye 1820 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 jpye 1815 # get the first filename in the tarball
100 jpye 1820 t = tarfile.open(ffull)
101 jpye 1815 M = t.getmembers()
102     print M[0].name
103    
104     # split the top-level directory name from that path
105    
106 jpye 2031 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 jpye 1815 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 jpye 1820 r = re.compile(r"^%s/debian/([^/]*)$" % re.escape(head))
123     r2 = re.compile(r"^debian/([^/]*)$")
124 jpye 1815
125 jpye 1820 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 jpye 1815
130 jpye 1820 # search for debian/* files inside the original tarball
131    
132 jpye 1815 for m in M:
133     if r.match(m.name):
134     h,p = os.path.split(m.name)
135 jpye 1820 debfiles[p] = [t,m]
136 jpye 1815
137 jpye 1820 # 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 jpye 1819 mandatorydebfiles = ['control','changelog','rules']
153 jpye 1815
154 jpye 1819 missingdebfiles = []
155     for _f in mandatorydebfiles:
156     if _f not in debfiles:
157     missingdebfiles.append(_f)
158     if missingdebfiles:
159 jpye 1820 s = "Tarball(s) missing required debian/* files: %s" %missingdebfiles
160 jpye 1819 raise RuntimeError(s)
161    
162 jpye 1820 fc = getdebfile('control')
163 jpye 1815
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 jpye 1820 fchange = getdebfile('changelog')
175 jpye 1815
176     changes = changelog.Changelog(file=fchange.read())
177    
178     debianname = "%s-%s" % (control['Source'],changes.upstream_version)
179    
180 jpye 2103 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 jpye 1815
186     # check for build-time dependencies
187    
188 jpye 2126 dependencies = ['build-essential','fakeroot','debhelper']
189 jpye 1815
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 jpye 2003 if d not in c or not c[d].isInstalled:
199 jpye 1815 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 jpye 1820 # extract source code tarball
215    
216     print "Extracting tarball to '%s'..." % maindir
217 jpye 1815 os.chdir(maindir)
218     t.extractall()
219     assert(os.path.exists(head))
220     print "Files extracted to '%s'" % os.getcwd()
221    
222 jpye 1820 # extract meta-file tarball if provided
223    
224     if tmeta:
225     print "Extracting meta tarball to '%s'..." % maindir
226 jpye 2102 os.chdir(os.path.join(maindir,head))
227 jpye 1820 tmeta.extractall()
228     os.chdir(maindir)
229    
230     assert(os.path.exists(os.path.join(head,"debian/control")))
231    
232 jpye 2103 # copy original tarball (recompressing to .gz/reheading if required?)
233 jpye 1820
234 jpye 2103 unzip = None
235     ext = None
236     if f[-7:] == ".tar.gz" or f[-4:] == ".tgz":
237 jpye 1820 print "Original tarball is in gzip format"
238 jpye 2103 unzip = ["gzip","-d"]
239     exe = "/bin/gzip"
240     ext = "gz"
241 jpye 1820 elif f[-8:] == ".tar.bz2":
242     print "Original tarball is in bzip2 format"
243 jpye 2103 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 jpye 1820 temptar = "%s_%s.orig.tar" % (control['Source'],changes.upstream_version)
261 jpye 2103 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 jpye 2104 print "Creating tarball copy '%s'" % temptz
272 jpye 2103 shutil.copyfile(ffull,temptz)
273     print "Extracting with %s..." % unzip[0]
274     subprocess.call(unzip + [temptz], executable=exe)
275 jpye 1820 assert(os.path.exists(temptar))
276 jpye 2103 print "Recompressing with gzip..."
277     subprocess.call(['gzip',temptar])
278    
279 jpye 1820 else:
280 jpye 2103 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 jpye 1820
284 jpye 2103 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 jpye 1815 # build the source package
291 jpye 1820 #print "Building source package..."
292     #res = subprocess.call(["dpkg-source","-b",head,ffull],executable="/usr/bin/dpkg-source")
293 jpye 1815
294 jpye 1820 #if res:
295     # raise RuntimeError("dpkg-source returned error code %d" % res)
296 jpye 1815
297     # build the binary package
298 jpye 2103 print "Entering directory '%s'" % debianname
299     os.chdir(debianname)
300 jpye 1820 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 jpye 1815
307 jpye 1820 if res:
308     raise RuntimeError("dpkg-buildpackage returned error code %s" % res)
309    
310 jpye 1815 except Exception, e:
311 jpye 2007 print "ERROR DURING DPKG-BUILDPACKAGE: %s"% str(e)
312     print "Temporary files can be inspected in %s" % maindir
313     sys.exit(1)
314 jpye 1815
315 jpye 1820 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 jpye 2126 shutil.move(_f, _p2)
328 jpye 1820
329     if failedtomovefiles:
330     raise RuntimeError("Failed to move the following files (check --nooverwrite): %s",failedtomovefiles)
331    
332 jpye 1815 #clean up files
333    
334 jpye 2089 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 jpye 1815 print "All done, exiting"
347    
348    

Properties

Name Value
svn:executable *

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