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(package_path): run_cmd('git checkout debian/changelog', shell=True)
91 with current_directory(build_place):
92 sb = ['sbuild', '-n', '-d', distribution, '--setup-hook',
93 build_place + '/add_source']
94 if sbuild_opts is not None: sb += sbuild_opts
100 def gen_package_files() :
101 '''Generate package files in build_place and a script
102 build_place/add_source that can be used as a sbuild setup hook to
103 include the package files. Use the sbuild key to sign our packages'''
104 script = '''#!/bin/sh
106 sudo -u root /usr/local/sbin/add-source {build_place}
108 build_place = build_place
110 f = open(build_place + "/add_source", "w")
113 with current_directory(build_place):
114 run_cmd(('chmod', 'a+x', 'add_source'))
115 run_cmd( 'dpkg-scanpackages . >Packages',
117 run_cmd('apt-ftparchive release . >Release', shell=True)
118 try: os.unlink('Release.gpg')
120 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)
124 '''Read in the packages file from source_packages
126 try: pf = open("source_packages")
128 print "Error: source_packages file not found"
130 def is_comment(line):
131 if re.match("^\\s*#", line): return False
132 if "#" in line: raise ValueError(
133 "Source package line contains a comment but not at beginning")
135 return map(lambda(x): x.rstrip(),
136 filter(is_comment, pf.readlines()))
141 opt.add_option('-b', '--build-place',
142 dest='build_place', help="Write resulting packages to BUILD_PLACE",
144 opt.add_option('--version-suffix', dest ='version_suffix')
145 opt.add_option('-d', '--distribution',
146 help="Set the Debian distribution to DISTRIBUTION",
150 opt.add_option('-s', '--sbuild-opt',
151 action='append', dest='sbuild_opts',
152 help='Specify an option to be sent to sbuild')
153 opt.add_option('--tar-file',
155 help = 'Tar up resulting packages in given tar file',
157 opt.usage = "%prog [options] [packages]"
158 (options, packages) = opt.parse_args()
159 build_place = options.build_place
160 distribution = options.distribution
161 version_suffix = options.version_suffix
162 if not version_suffix: version_suffix = suffix_map.get(distribution, '0')
163 sbuild_opts = options.sbuild_opts
164 tar_file = options.tar_file
167 if len(packages) == 0: packages = read_packages()
169 os.makedirs(build_place)
177 except CommandError as c:
178 print "Error:" + str(c.args)
181 if tar_file is not None:
182 with current_directory(build_place):
183 run_cmd('tar -cf '+tar_file+' .',