3
# prevu -- automated backporter
4
# Basic usage: prevu <sourcepackagename>
6
# Copyright (C) 2006 John Dong <jdong@ubuntu.com>
8
# This program is free software; you can redistribute it and/or
9
# modify it under the terms of the GNU General Public License
10
# as published by the Free Software Foundation; either version 2
11
# of the License, or (at your option) any later version.
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
# GNU General Public License for more details.
18
# You should have received a copy of the GNU General Public License
19
# along with this program; if not, write to the Free Software
20
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25
import os, sys, glob, shutil
27
def change_xterm_title(new_title):
29
Changes the title on xterm-compatible terminals.
30
new_title: The text to change the title to
32
if os.getenv('TERM') == 'xterm':
33
#Only do it if TERM is xterm...
34
print "\033]0;%s\007" % new_title
36
class NoSuchPackageException(Exception): pass
37
class NoBuildEnvironment(Exception): pass
40
'''Abstract class encapsulating a package to be backported'''
41
suffixes={'warty': '4.10prevu1',
42
'hoary': '5.04prevu1',
43
'breezy': '5.10prevu1',
44
'dapper': '6.06prevu1',
46
'feisty': '7.04prevu1'}
49
raise NotImplementedError
50
def check_builder(self):
51
if not os.path.exists('/var/cache/prevu/%s.tgz' % self.target_distro): raise NoBuildEnvironment("Not ready to build for %s. You need to run 'DISTRO=%s sudo prevu-init'." % (self.target_distro, self.target_distro))
52
def prepare_sources(self):
53
'''Finds and unpacks sources'''
54
raise NotImplementedError
55
def debian_version(self):
56
'''Gets the current debian-version of the source package'''
57
version=os.popen('cat debian/changelog | head -n 1 | cut -d \( -f 2 | cut -d \) -f 1').read()[:-1]
59
raise ValueError("Could not figure out source version. Is debian/changelog corrupted/nonexistent?")
61
def backport_version(self):
62
'''Gets the backport version'''
64
if self.debian_version().endswith('~'+self.suffixes[self.target_distro]):
65
return self.debian_version()
67
return self.debian_version()+'~'+self.suffixes[self.target_distro]
69
raise KeyError, "Invalid distribution: %s" % self.target_distro
70
def init_working_path(self):
71
'''Gets the build directory ready'''
72
self.working_path='/var/cache/prevu/src/%s' % (os.getpid())
73
while os.path.exists(self.working_path):
74
self.working_path+=".1"
75
os.mkdir(self.working_path)
76
def enter_sourcetree(self):
77
'''Enters extracted source package'''
78
os.chdir(self.working_path)
79
dirs=os.listdir(self.working_path)
87
raise ValueError("No extracted source tree can be located!")
88
def mangle_version(self):
89
'''Changes package version to backported package'''
90
if self.debian_version() != self.backport_version():
91
os.system('dch -v %s -b "Automated backport by prevu. No source changes"' % self.backport_version())
93
'''Invokes the build. Call when source package is unpacked and version number is set'''
94
ret=os.system('pdebuild --use-pdebuild-internal -- --basetgz /var/cache/prevu/%s.tgz --buildplace /var/cache/prevu/builds --bindmounts /var/cache/prevu/%s-debs' % (self.target_distro, self.target_distro))
96
raise ValueError("Build failed.")
99
# First, move all the built debs to their final resting site :)
100
for pkg in glob.glob(self.working_path+"/*.deb"):
101
shutil.move(pkg,'/var/cache/prevu/%s-debs' % self.target_distro)
102
os.chdir('/var/cache/prevu/%s-debs' % self.target_distro)
103
os.system('dpkg-scanpackages . /dev/null > Packages 2>/dev/null')
105
'''Clean up working area'''
106
os.system('rm -rf '+self.working_path)
108
'''Routine for building the backport'''
111
self.init_working_path()
112
self.prepare_sources()
113
self.enter_sourcetree()
114
self.mangle_version()
119
class BackportFromAPT(Backport):
120
'''Use APT to get source for backport'''
121
def __init__(self,pkgname, target_distro):
124
pkgname: package name to pass to `apt-get source` command
125
target_distro: the distribution version to backport to
128
self.target_distro=target_distro
129
def prepare_sources(self):
130
os.chdir(self.working_path)
131
ret=os.system("/usr/bin/apt-get source %s" % self.pkgname)
133
raise ValueError("Fetching source package failed. Are you sure it exists?")
135
class BackportCurrentDir(Backport):
136
'''Build the sources from the current directory'''
137
def __init__(self,target_distro):
138
self.target_distro=target_distro
139
def prepare_sources(self):
140
print "Making a temporary copy of current directory..."
141
ret=os.system("cp -rp . "+self.working_path+"/source")
143
raise ValueError("Could not prepare sources")
145
class BackportFromDsc(Backport):
146
'''Build from a specified .dsc file -- either a local file or a URL'''
147
def __init__(self, dsc, target_distro):
149
self.target_distro=target_distro
150
def prepare_sources(self):
152
if self.dsc.startswith("http://") or self.dsc.startswith("ftp://") or self.dsc.startswith("https://"):
153
#Is a URL, should be processed with dget
154
os.chdir(self.working_path)
155
ret=os.system('dget -x %s' % self.dsc)
157
#Assume is a file, and the rest of the source is in current directory
159
ret=os.system('dpkg-source -x -sn %s %s/extracted' % (self.dsc,self.working_path))
161
raise ValueError("Extracting source package failed")
163
if __name__=='__main__':
164
DIST=os.getenv('DIST') or ""
165
if not DIST in Backport.suffixes.keys():
166
# Distro got through environment is not valid, building against running distro
167
print >> sys.stderr, "I: Building against currently running distro:",
168
DIST=os.popen('lsb_release -c').read().split(':')[1].strip()
169
print >> sys.stderr, DIST
171
print >> sys.stderr, "I: Building against specified distro:", DIST
172
if len(sys.argv) == 2:
173
change_xterm_title('prevu (%s): %s' % (DIST, sys.argv[1]))
174
if sys.argv[1].endswith(".dsc"):
175
BackportFromDsc(sys.argv[1],DIST).backport()
177
BackportFromAPT(sys.argv[1],DIST).backport()
178
elif len(sys.argv) == 1 and os.path.exists("./debian"):
179
change_xterm_title('prevu (%s): %s' % (DIST, os.getcwd()))
180
BackportCurrentDir(DIST).backport()
182
print "Usage (fetch from APT): %s source_package_name" % sys.argv[0]
183
print "Usage (build current directory): %s" % sys.argv[0]
184
print "Usage (build from .dsc file): %s dscfile_or_url" % sys.argv[0]
185
print "Prevu builds for your currently running version of Ubuntu. To override this, use the DIST environment variable"
186
print "Build for Warty Warthog: DIST=warty %s" % sys.argv[0]
188
print "** Success!. You can find source packages and .debs at /var/cache/prevu/%s-debs **" % DIST