3 '''A script to build Debian packages using sbuild from a source
4 directory rather than a source package. Also, if multiple packages are
5 built, previous packages are available to satisfy
6 dependencies. Requires that the build-place be available from the
10 from contextlib import contextmanager
11 import os, subprocess, exceptions
14 from optparse import OptionParser
15 from shutil import copy
17 import debian.changelog, debian.deb822
19 # These variables can be overridden by options. If packages is not
20 # set, then it is read from the source_packages file
21 packages = [] # Set of packages to build
23 build_place = os.path.join(os.getcwd(), 'debian_build')
25 class CommandError(exceptions.StandardError):
29 def current_directory(dir):
30 "Change the current directory as a context manager; when the context exits, return."
37 def run_cmd(args, **kwords):
38 rcode = subprocess.call( args, **kwords)
40 raise CommandError(args)
42 def command_output(args) :
43 p = subprocess.Popen(args, stdout=subprocess.PIPE)
44 output = p.communicate()
47 raise CommandError(args)
51 '''Describe all the files included in dsc, wich is a string name
52 of a dsc package. dsc itself is included'''
53 package = debian.deb822.Dsc(open(dsc))
54 internal_files = map( lambda(x): x['name'], package['Files'])
55 internal_files.append(dsc)
59 with current_directory(package):
60 cl = debian.changelog.Changelog(open('debian/changelog'))
61 package_name = cl.package
62 package_version = re.sub('^\d+:','',str(cl.version))
63 orig_tar = package_name+'_'+ cl.upstream_version + ".orig.tar"
64 dsc_name = package_name+"_"+package_version + ".dsc"
65 print "==> Package: ", package_name
66 source_format = command_output(('dpkg-source', '--print-format', '.'))
67 if "native" not in source_format:
68 run_cmd( ('git', 'fetch', 'origin', 'pristine-tar:pristine-tar'))
69 for file in command_output(( 'pristine-tar', 'list')).split("\n"):
70 if file.startswith(orig_tar): orig_tar = file
71 run_cmd( ('pristine-tar', 'checkout', '../'+orig_tar))
72 package_path = os.path.split(package)
73 with current_directory(os.path.join ('.', *package_path[0:len(package_path)-1])) :
74 package_path = package_path[len(package_path)-1]
76 run_cmd(("dpkg-source", '-b', '-i', package_path))
77 for f in dsc_files(dsc_name):
80 for f in dsc_files(dsc_name):
83 with current_directory(build_place):
84 sb = ['sbuild', '-n', '-d', distribution, '--setup-hook',
85 build_place + '/add_source']
86 if sbuild_opts is not None: sb += sbuild_opts
92 def gen_package_files() :
93 '''Generate package files in build_place and a script
94 build_place/add_source that can be used as a sbuild setup hook to
95 include the package files. Use the sbuild key to sign our packages'''
98 sudo -u root /usr/local/sbin/add-source {build_place}
100 build_place = build_place
102 f = open(build_place + "/add_source", "w")
105 with current_directory(build_place):
106 run_cmd(('chmod', 'a+x', 'add_source'))
107 run_cmd( 'dpkg-scanpackages . >Packages',
109 run_cmd('apt-ftparchive release . >Release', shell=True)
110 try: os.unlink('Release.gpg')
112 run_cmd( 'gpg -sabt -o Release.gpg --secret-keyring /var/lib/sbuild/apt-keys/sbuild-key.sec --keyring /var/lib/sbuild/apt-keys/sbuild-key.pub Release', shell=True)
116 '''Read in the packages file from source_packages
118 try: pf = open("source_packages")
120 print "Error: source_packages file not found"
122 def is_comment(line):
123 if re.match("^\\s*#", line): return False
124 if "#" in line: raise ValueError(
125 "Source package line contains a comment but not at beginning")
127 return map(lambda(x): x.rstrip(),
128 filter(is_comment, pf.readlines()))
133 opt.add_option('-b', '--build-place',
134 dest='build_place', help="Write resulting packages to BUILD_PLACE",
136 opt.add_option('-d', '--distribution',
137 help="Set the Debian distribution to DISTRIBUTION",
141 opt.add_option('-s', '--sbuild-opt',
142 action='append', dest='sbuild_opts',
143 help='Specify an option to be sent to sbuild')
144 opt.add_option('--tar-file',
146 help = 'Tar up resulting packages in given tar file',
148 opt.usage = "%prog [options] [packages]"
149 (options, packages) = opt.parse_args()
150 build_place = options.build_place
151 distribution = options.distribution
152 sbuild_opts = options.sbuild_opts
153 tar_file = options.tar_file
156 if len(packages) == 0: packages = read_packages()
158 os.makedirs(build_place)
166 except CommandError as c:
167 print "Error:" + str(c.args)
170 if tar_file is not None:
171 with current_directory(build_place):
172 run_cmd('tar -cf '+tar_file+' .',