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
22 distribution = "unstable"
23 build_place = os.path.join(os.getcwd(), 'debian_build')
31 class CommandError(exceptions.StandardError):
35 def current_directory(dir):
36 "Change the current directory as a context manager; when the context exits, return."
43 def run_cmd(args, **kwords):
44 rcode = subprocess.call( args, **kwords)
46 raise CommandError(args)
48 def command_output(args) :
49 p = subprocess.Popen(args, stdout=subprocess.PIPE)
50 output = p.communicate()
53 raise CommandError(args)
57 '''Describe all the files included in dsc, wich is a string name
58 of a dsc package. dsc itself is included'''
59 package = debian.deb822.Dsc(open(dsc))
60 internal_files = map( lambda(x): x['name'], package['Files'])
61 internal_files.append(dsc)
65 with current_directory(package):
66 cl = debian.changelog.Changelog(open('debian/changelog'))
67 package_name = cl.package
68 package_version = re.sub('^\d+:','',str(cl.version))
69 orig_tar = package_name+'_'+ cl.upstream_version + ".orig.tar"
70 dsc_name = package_name+"_"+package_version + '~' + version_suffix+ ".dsc"
71 run_cmd(['dch', '-b', '-v' +str(cl.version)+'~'+version_suffix, '-D'+distribution, 'Autobuilt package'])
72 print "==> Package: ", package_name
73 source_format = command_output(('dpkg-source', '--print-format', '.'))
74 if "native" not in source_format:
75 run_cmd( ('git', 'fetch', 'origin', 'pristine-tar:pristine-tar'))
76 for file in command_output(( 'pristine-tar', 'list')).split("\n"):
77 if file.startswith(orig_tar): orig_tar = file
78 run_cmd( ('pristine-tar', 'checkout', '../'+orig_tar))
79 package_path = os.path.split(package)
80 with current_directory(os.path.join ('.', *package_path[0:len(package_path)-1])) :
81 package_path = package_path[len(package_path)-1]
83 run_cmd(("dpkg-source", '-b', '-i', package_path))
84 for f in dsc_files(dsc_name):
87 for f in dsc_files(dsc_name):
90 with current_directory(build_place):
91 sb = ['sbuild', '-n', '-d', distribution, '--setup-hook',
92 build_place + '/add_source']
93 if sbuild_opts is not None: sb += sbuild_opts
99 def gen_package_files() :
100 '''Generate package files in build_place and a script
101 build_place/add_source that can be used as a sbuild setup hook to
102 include the package files. Use the sbuild key to sign our packages'''
103 script = '''#!/bin/sh
105 sudo -u root /usr/local/sbin/add-source {build_place}
107 build_place = build_place
109 f = open(build_place + "/add_source", "w")
112 with current_directory(build_place):
113 run_cmd(('chmod', 'a+x', 'add_source'))
114 run_cmd( 'dpkg-scanpackages . >Packages',
116 run_cmd('apt-ftparchive release . >Release', shell=True)
117 try: os.unlink('Release.gpg')
119 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)
123 '''Read in the packages file from source_packages
125 try: pf = open("source_packages")
127 print "Error: source_packages file not found"
129 def is_comment(line):
130 if re.match("^\\s*#", line): return False
131 if "#" in line: raise ValueError(
132 "Source package line contains a comment but not at beginning")
134 return map(lambda(x): x.rstrip(),
135 filter(is_comment, pf.readlines()))
140 opt.add_option('-b', '--build-place',
141 dest='build_place', help="Write resulting packages to BUILD_PLACE",
143 opt.add_option('--version-suffix', dest ='version_suffix')
144 opt.add_option('-d', '--distribution',
145 help="Set the Debian distribution to DISTRIBUTION",
149 opt.add_option('-s', '--sbuild-opt',
150 action='append', dest='sbuild_opts',
151 help='Specify an option to be sent to sbuild')
152 opt.add_option('--tar-file',
154 help = 'Tar up resulting packages in given tar file',
156 opt.usage = "%prog [options] [packages]"
157 (options, packages) = opt.parse_args()
158 build_place = options.build_place
159 distribution = options.distribution
160 version_suffix = options.version_suffix
161 if not version_suffix: version_suffix = suffix_map.get(distribution, '0')
162 sbuild_opts = options.sbuild_opts
163 tar_file = options.tar_file
166 if len(packages) == 0: packages = read_packages()
168 os.makedirs(build_place)
176 except CommandError as c:
177 print "Error:" + str(c.args)
180 if tar_file is not None:
181 with current_directory(build_place):
182 run_cmd('tar -cf '+tar_file+' .',