~ubuntu-branches/ubuntu/lucid/prevu/lucid-proposed

« back to all changes in this revision

Viewing changes to prevu

  • Committer: Bazaar Package Importer
  • Author(s): Martin Meredith
  • Date: 2006-11-16 16:35:23 UTC
  • Revision ID: james.westby@ubuntu.com-20061116163523-20zit8s316zpfr76
Tags: upstream-0.4.1bzr46
ImportĀ upstreamĀ versionĀ 0.4.1bzr46

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
#
 
3
# prevu -- automated backporter
 
4
# Basic usage: prevu <sourcepackagename>
 
5
#
 
6
# Copyright (C) 2006 John Dong <jdong@ubuntu.com>
 
7
 
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.
 
12
 
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.
 
17
 
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.
 
21
#
 
22
 
 
23
 
 
24
 
 
25
import os, sys, glob, shutil
 
26
 
 
27
def change_xterm_title(new_title):
 
28
  """
 
29
  Changes the title on xterm-compatible terminals.
 
30
  new_title: The text to change the title to
 
31
  """
 
32
  if os.getenv('TERM') == 'xterm':
 
33
    #Only do it if TERM is xterm...
 
34
    print "\033]0;%s\007" % new_title
 
35
 
 
36
class NoSuchPackageException(Exception): pass
 
37
class NoBuildEnvironment(Exception): pass
 
38
 
 
39
class Backport:
 
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',
 
45
             'edgy':    '6.10prevu1',
 
46
             'feisty':  '7.04prevu1'}
 
47
 
 
48
  def __init__(self):
 
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]
 
58
    if not version:
 
59
      raise ValueError("Could not figure out source version. Is debian/changelog corrupted/nonexistent?")
 
60
    return version
 
61
  def backport_version(self):
 
62
    '''Gets the backport version'''
 
63
    try:
 
64
      if self.debian_version().endswith('~'+self.suffixes[self.target_distro]):
 
65
        return self.debian_version()
 
66
      else:
 
67
        return self.debian_version()+'~'+self.suffixes[self.target_distro]
 
68
    except KeyError:
 
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)
 
80
    found=False
 
81
    for i in dirs:
 
82
      if os.path.isdir(i):
 
83
        os.chdir(i)
 
84
        found=True
 
85
        break
 
86
    if not found:
 
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())
 
92
  def do_compile(self):
 
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))
 
95
    if ret != 0:
 
96
      raise ValueError("Build failed.")
 
97
    else:
 
98
      # Build succeeded
 
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')
 
104
  def cleanup(self):
 
105
    '''Clean up working area'''
 
106
    os.system('rm -rf '+self.working_path)
 
107
  def backport(self):
 
108
    '''Routine for building the backport'''
 
109
    self.check_builder()
 
110
    try:
 
111
      self.init_working_path()
 
112
      self.prepare_sources()
 
113
      self.enter_sourcetree()
 
114
      self.mangle_version()
 
115
      self.do_compile()
 
116
    finally:
 
117
      self.cleanup()
 
118
 
 
119
class BackportFromAPT(Backport):
 
120
  '''Use APT to get source for backport'''
 
121
  def __init__(self,pkgname, target_distro):
 
122
    '''
 
123
    Class Initializer.
 
124
    pkgname: package name to pass to `apt-get source` command
 
125
    target_distro: the distribution version to backport to
 
126
    '''
 
127
    self.pkgname=pkgname
 
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)
 
132
    if ret != 0:
 
133
      raise ValueError("Fetching source package failed. Are you sure it exists?")
 
134
 
 
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")
 
142
    if ret != 0:
 
143
      raise ValueError("Could not prepare sources")
 
144
 
 
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):
 
148
    self.dsc=dsc
 
149
    self.target_distro=target_distro
 
150
  def prepare_sources(self):
 
151
    ret=-1
 
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)
 
156
    else:
 
157
      #Assume is a file, and the rest of the source is in current directory
 
158
      #Use dpkg-source -x
 
159
      ret=os.system('dpkg-source -x -sn %s %s/extracted' % (self.dsc,self.working_path))
 
160
    if ret != 0:
 
161
      raise ValueError("Extracting source package failed")
 
162
 
 
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
 
170
  else:
 
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()
 
176
    else:
 
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()
 
181
  else:
 
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]
 
187
    sys.exit(1)
 
188
  print "** Success!. You can find source packages and .debs at /var/cache/prevu/%s-debs **" % DIST