direct-io.hg

changeset 15506:8426e8a36290

Add support to the tarball source type for using the ketchup tool.

Signed-off-by: Ian Campbell <ian.campbell@xensource.com>
author Ian Campbell <ian.campbell@xensource.com>
date Mon Jul 09 11:57:07 2007 +0100 (2007-07-09)
parents 224da1b2c5c2
children 231bfe08fdbf
files buildconfigs/ketchup buildconfigs/src.tarball
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/buildconfigs/ketchup	Mon Jul 09 11:57:07 2007 +0100
     1.3 @@ -0,0 +1,742 @@
     1.4 +#!/usr/bin/python
     1.5 +#
     1.6 +# ketchup 0.9.8
     1.7 +# http://selenic.com/ketchup/wiki
     1.8 +#
     1.9 +# Copyright 2004 Matt Mackall <mpm@selenic.com>
    1.10 +#
    1.11 +# This software may be used and distributed according to the terms
    1.12 +# of the GNU General Public License, incorporated herein by reference.
    1.13 +#
    1.14 +# Usage:
    1.15 +#
    1.16 +# in an existing kernel directory, run:
    1.17 +#
    1.18 +#  ketchup <version>
    1.19 +#
    1.20 +# where version is a complete kernel version, or a branch name to grab
    1.21 +# the latest version
    1.22 +#
    1.23 +# You can override some variables by creating a ~/.ketchuprc file.
    1.24 +# The ~/.ketchuprc is just a Python script, eg. it might look like this:
    1.25 +#
    1.26 +# kernel_url = 'http://kernel.localdomain/pub/linux/kernel'
    1.27 +# archive = os.environ["HOME"] + '/tmp/ketchup-archive'
    1.28 +# gpg = '/weird/path/to/gpg'
    1.29 +#
    1.30 +
    1.31 +import re, sys, urllib, os, getopt, glob, shutil
    1.32 +
    1.33 +def error(*args):
    1.34 +    sys.stderr.write("ketchup: ")
    1.35 +    for a in args:
    1.36 +        sys.stderr.write(str(a))
    1.37 +        sys.stderr.write("\n")
    1.38 +
    1.39 +def qprint(*args):
    1.40 +    if not options["quiet"]:
    1.41 +        sys.stdout.write(" ".join(map(str, args)))
    1.42 +        sys.stdout.write("\n")
    1.43 +
    1.44 +def lprint(*args):
    1.45 +    sys.stdout.write(" ".join(map(str, args)))
    1.46 +    sys.stdout.write("\n")
    1.47 +
    1.48 +
    1.49 +def fancyopts(args, options, state, syntax=''):
    1.50 +    long = []
    1.51 +    short = ''
    1.52 +    map = {}
    1.53 +    dt = {}
    1.54 +
    1.55 +    def help(state, opt, arg, options = options, syntax = syntax):
    1.56 +        lprint("Usage: ", syntax)
    1.57 +
    1.58 +        for s, l, d, c in options:
    1.59 +            opt = ' '
    1.60 +            if s: opt = opt + '-' + s + ' '
    1.61 +            if l: opt = opt + '--' + l + ' '
    1.62 +            if d: opt = opt + '(' + str(d) + ')'
    1.63 +            lprint(opt)
    1.64 +            if c: lprint('   %s' % c)
    1.65 +        sys.exit(0)
    1.66 +
    1.67 +    options = [('h', 'help', help, 'Show usage info')] + options
    1.68 +
    1.69 +    for s, l, d, c in options:
    1.70 +        map['-'+s] = map['--'+l]=l
    1.71 +        state[l] = d
    1.72 +        dt[l] = type(d)
    1.73 +        if not d is None and not type(d) is type(help): s, l = s + ':', l + '='
    1.74 +        if s: short = short + s
    1.75 +        if l: long.append(l)
    1.76 +
    1.77 +    if os.environ.has_key("KETCHUP_OPTS"):
    1.78 +        args = os.environ["KETCHUP_OPTS"].split() + args
    1.79 +
    1.80 +    try:
    1.81 +        opts, args = getopt.getopt(args, short, long)
    1.82 +    except getopt.GetoptError:
    1.83 +        help(state, None, args)
    1.84 +        sys.exit(-1)
    1.85 +
    1.86 +    for opt, arg in opts:
    1.87 +        if dt[map[opt]] is type(help): state[map[opt]](state,map[opt],arg)
    1.88 +        elif dt[map[opt]] is type(1): state[map[opt]] = int(arg)
    1.89 +        elif dt[map[opt]] is type(''): state[map[opt]] = arg
    1.90 +        elif dt[map[opt]] is type([]): state[map[opt]].append(arg)
    1.91 +        elif dt[map[opt]] is type(None): state[map[opt]] = 1
    1.92 +
    1.93 +    return args
    1.94 +
    1.95 +# Default values
    1.96 +kernel_url = 'http://www.kernel.org/pub/linux/kernel'
    1.97 +archive = os.environ["HOME"] + "/.ketchup"
    1.98 +rename_prefix = 'linux-'
    1.99 +rename_with_localversion = False
   1.100 +wget = "/usr/bin/wget"
   1.101 +gpg = "/usr/bin/gpg"
   1.102 +precommand = postcommand = None
   1.103 +default_tree = None
   1.104 +local_trees = {}
   1.105 +
   1.106 +# Functions to parse version strings
   1.107 +
   1.108 +def tree(ver):
   1.109 +    return float(re.match(r'(\d+\.\d+)', ver).group(1))
   1.110 +
   1.111 +def rev(ver):
   1.112 +    p = pre(ver)
   1.113 +    r = int(re.match(r'\d+\.\d+\.(\d+)', ver).group(1))
   1.114 +    if p: r = r - 1
   1.115 +    return r
   1.116 +
   1.117 +def pre(ver):
   1.118 +    try: return re.match(r'\d+\.\d+\.\d+(\.\d+)?-((rc|pre)\d+)', ver).group(2)
   1.119 +    except: return None
   1.120 +
   1.121 +def post(ver):
   1.122 +    try: return re.match(r'\d+\.\d+\.\d+\.(\d+)', ver).group(1)
   1.123 +    except: return None
   1.124 +
   1.125 +def pretype(ver):
   1.126 +    try: return re.match(r'\d+\.\d+\.\d+(\.\d+)?-((rc|pre)\d+)', ver).group(3)
   1.127 +    except: return None
   1.128 +
   1.129 +def prenum(ver):
   1.130 +    try: return int(re.match(r'\d+\.\d+\.\d+-((rc|pre)(\d+))', ver).group(3))
   1.131 +    except: return None
   1.132 +
   1.133 +def prebase(ver):
   1.134 +    return re.match(r'(\d+\.\d+\.\d+((-(rc|pre)|\.)\d+)?)', ver).group(1)
   1.135 +
   1.136 +def revbase(ver):
   1.137 +    return "%s.%s" % (tree(ver), rev(ver))
   1.138 +
   1.139 +def base(ver):
   1.140 +    v = revbase(ver)
   1.141 +    if post(ver): v += "." + post(ver)
   1.142 +    return v
   1.143 +
   1.144 +def forkname(ver):
   1.145 +    try: return re.match(r'\d+.\d+.\d+(\.\d+)?(-(rc|pre)\d+)?(-(\w+?)\d+)?',
   1.146 +                         ver).group(5)
   1.147 +    except: return None
   1.148 +
   1.149 +def forknum(ver):
   1.150 +    try: return int(
   1.151 +        re.match(r'\d+.\d+.\d+(\.\d+)?(-(rc|pre)\d+)?(-(\w+?)(\d+))?',
   1.152 +                 ver).group(6))
   1.153 +    except: return None
   1.154 +
   1.155 +def fork(ver):
   1.156 +    try: return re.match(r'\d+.\d+.\d+(\.\d+)?(-(rc|pre)\d+)?(-(\w+))?', ver).group(4)
   1.157 +    except: return None
   1.158 +
   1.159 +def get_ver(makefile):
   1.160 +    """ Read the version information from the specified makefile """
   1.161 +    part = {}
   1.162 +    parts = "VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION".split(' ')
   1.163 +    m = open(makefile)
   1.164 +    for l in m.readlines():
   1.165 +        for p in parts:
   1.166 +            try: part[p] = re.match(r'%s\s*=\s*(\S+)' % p, l).group(1)
   1.167 +            except: pass
   1.168 +
   1.169 +    version = "%s.%s.%s" % tuple([part[p] for p in parts[:3]])
   1.170 +    version += part.get("EXTRAVERSION","")
   1.171 +    return version
   1.172 +
   1.173 +def get_localversion():
   1.174 +    v = ''
   1.175 +
   1.176 +    for name in glob.glob('localversion*'):
   1.177 +        try: v += open(name).readline().strip()
   1.178 +        except: pass
   1.179 +
   1.180 +    try:
   1.181 +        c = open('.config').read()
   1.182 +        v += re.search(r'^CONFIG_LOCALVERSION="(.+)"', c, re.M).group(1)
   1.183 +    except: pass
   1.184 +
   1.185 +    return v
   1.186 +
   1.187 +def compare_ver(a, b):
   1.188 +    """
   1.189 +    Compare kernel versions a and b
   1.190 +
   1.191 +    Note that -pre and -rc versions sort before the version they modify,
   1.192 +    -pre sorts before -rc, -bk, -git, and -mm, etc. sort alphabetically.
   1.193 +    """
   1.194 +    if a == b: return 0
   1.195 +
   1.196 +    c = cmp(float(tree(a)), float(tree(b)))
   1.197 +    if c: return c
   1.198 +    c = cmp(rev(a), rev(b))
   1.199 +    if c: return c
   1.200 +    c = cmp(int(post(a) or 0), int(post(b) or 0))
   1.201 +    if c: return c
   1.202 +    c = cmp(pretype(a), pretype(b)) # pre sorts before rc
   1.203 +    if c: return c
   1.204 +    c = cmp(prenum(a), prenum(b))
   1.205 +    if c: return c
   1.206 +    c = cmp(forkname(a), forkname(b))
   1.207 +    if c: return c
   1.208 +    return cmp(forknum(a), forknum(b))
   1.209 +
   1.210 +def last(url, pat="(.*/)"):
   1.211 +    for l in urllib.urlopen(url).readlines():
   1.212 +        m = re.search('(?i)<a href="%s">' % pat, l)
   1.213 +        if m: n = m.group(1)
   1.214 +    return n
   1.215 +
   1.216 +def latest_mm(url, pat):
   1.217 +    url = kernel_url + '/people/akpm/patches/2.6/'
   1.218 +    url += last(url)
   1.219 +    part = last(url)
   1.220 +    return part[:-1]
   1.221 +
   1.222 +def latest_ck(url, pat):
   1.223 +    url = "http://ck.kolivas.org/patches/2.6/pre-releases/"
   1.224 +    url += last(url)
   1.225 +    part = last(url)
   1.226 +    pre = part[:-1]
   1.227 +
   1.228 +    url = "http://ck.kolivas.org/patches/2.6/"
   1.229 +    url += last(url,"(2.6.*/)")
   1.230 +    part = last(url)
   1.231 +    rel = part[:-1]
   1.232 +
   1.233 +    l = [pre, rel]
   1.234 +    l.sort(compare_ver)
   1.235 +    return l[-1]
   1.236 +
   1.237 +def latest_dir(url, pat):
   1.238 +    """Find the latest link matching pat at url after sorting"""
   1.239 +    p = []
   1.240 +    for l in urllib.urlopen(url).readlines():
   1.241 +        m = re.search('"%s"' % pat, l)
   1.242 +        if m: p.append(m.group(1))
   1.243 +
   1.244 +    if not p: return None
   1.245 +
   1.246 +    p.sort(compare_ver)
   1.247 +    return p[-1]
   1.248 +
   1.249 +# mbligh is lazy and has a bunch of empty directories
   1.250 +def latest_mjb(url, pat):
   1.251 +    url = kernel_url + '/people/mbligh/'
   1.252 +
   1.253 +    # find the last Linus release and search backwards
   1.254 +    l = [find_ver('2.6'), find_ver("2.6-pre")]
   1.255 +    l.sort(compare_ver)
   1.256 +    linus = l[-1]
   1.257 +
   1.258 +    p = []
   1.259 +    for l in urllib.urlopen(url).readlines():
   1.260 +        m = re.search('"(2\.6\..*/)"', l)
   1.261 +        if m:
   1.262 +            v = m.group(1)
   1.263 +            if compare_ver(v, linus) <= 0:
   1.264 +                p.append(v)
   1.265 +
   1.266 +    p.sort(compare_ver)
   1.267 +    p.reverse()
   1.268 +
   1.269 +    for ver in p:
   1.270 +        mjb = latest_dir(url + ver, pat)
   1.271 +        if mjb: return mjb
   1.272 +
   1.273 +    return None
   1.274 +
   1.275 +def latest_26_tip(url, pat):
   1.276 +    l = [find_ver('2.6'), find_ver('2.6-git'), find_ver('2.6-pre')]
   1.277 +    l.sort(compare_ver)
   1.278 +    return l[-1]
   1.279 +
   1.280 +def find_info(ver):
   1.281 +    b = "%.1f" % tree(ver)
   1.282 +    f = forkname(ver)
   1.283 +    p = pre(ver)
   1.284 +
   1.285 +    s = b
   1.286 +    if f:
   1.287 +        s = "%s-%s" % (b, f)
   1.288 +    elif p:
   1.289 +        s = "%s-pre" % b
   1.290 +
   1.291 +    return version_info[s]
   1.292 +
   1.293 +def version_urls(ver):
   1.294 +    """ Return the URL for the patch associated with the specified version """
   1.295 +    i = find_info(ver)[1]
   1.296 +    if type(i) != type([]):
   1.297 +        i = [i]
   1.298 +
   1.299 +    v = {
   1.300 +        'full': ver,
   1.301 +        'tree': tree(ver),
   1.302 +        'base': base(ver),
   1.303 +        'prebase': prebase(ver)
   1.304 +        }
   1.305 +
   1.306 +    l = []
   1.307 +    for e in i:
   1.308 +        l.append(e % v)
   1.309 +
   1.310 +    return l
   1.311 +
   1.312 +def patch_path(ver):
   1.313 +    return os.path.join(archive, os.path.basename(version_urls(ver)[0]))
   1.314 +
   1.315 +def download(url, f):
   1.316 +    qprint("Downloading %s" % os.path.basename(url))
   1.317 +    if options["dry-run"]:
   1.318 +        return 1
   1.319 +
   1.320 +    if not options["wget"]:
   1.321 +        p = urllib.urlopen(url).read()
   1.322 +        if p.find("<title>404") != -1:
   1.323 +            return None
   1.324 +        open(f, 'w').write(p)
   1.325 +    else:
   1.326 +        e = os.system("%s -c -O %s %s" %
   1.327 +                      (options["wget"], f + ".partial", url))
   1.328 +        if e:
   1.329 +            return None
   1.330 +        os.rename(f + ".partial", f)
   1.331 +
   1.332 +    return 1
   1.333 +
   1.334 +def verify(url, f, sign):
   1.335 +    if options["no-gpg"] or options["dry-run"] or not options["gpg-path"]:
   1.336 +        return 1
   1.337 +
   1.338 +    sf = f + sign
   1.339 +    if not download(url + sign, sf):
   1.340 +        error("signature download failed")
   1.341 +        error("removing files...")
   1.342 +        os.unlink(f)
   1.343 +        return 0
   1.344 +
   1.345 +    qprint("Verifying signature...")
   1.346 +    r = os.system("%s --verify %s %s" % (options["gpg-path"], sf, f))
   1.347 +    if r:
   1.348 +        error("gpg returned %d" % r)
   1.349 +        error("removing files...")
   1.350 +        os.unlink(f)
   1.351 +        os.unlink(sf)
   1.352 +        return 0
   1.353 +
   1.354 +    return 1
   1.355 +
   1.356 +def trydownload(urls, f, sign):
   1.357 +    for url in urls:
   1.358 +        if download(url, f):
   1.359 +            if not sign or verify(url, f, sign):
   1.360 +                return f
   1.361 +        if url[-4:] == ".bz2":
   1.362 +            f2 = f[:-4] + ".gz"
   1.363 +            url2 = url[:-4] + ".gz"
   1.364 +            if download(url2, f2):
   1.365 +                if not sign or verify(url2, f2, sign):
   1.366 +                    return f2
   1.367 +    return None
   1.368 +
   1.369 +def get_patch(ver):
   1.370 +    """Return the path to patch for given ver, downloading if necessary"""
   1.371 +    f = patch_path(ver)
   1.372 +    if os.path.exists(f):
   1.373 +        return f
   1.374 +    if f[-4:] == ".bz2":
   1.375 +        f2 = f[:-4] + ".gz"
   1.376 +        if os.path.exists(f2):
   1.377 +            return f2
   1.378 +
   1.379 +    urls = version_urls(ver)
   1.380 +    sign = find_info(ver)[3]
   1.381 +    if sign == 1: sign = ".sign"
   1.382 +    f = trydownload(urls, f, sign)
   1.383 +    if not f:
   1.384 +        error("patch download failed")
   1.385 +        sys.exit(-1)
   1.386 +
   1.387 +    return f
   1.388 +
   1.389 +def apply_patch(ver, reverse = 0):
   1.390 +    """Find the patch to upgrade from the predecessor of ver to ver and
   1.391 +    apply or reverse it."""
   1.392 +    p = get_patch(ver)
   1.393 +    r = ""
   1.394 +    if reverse:
   1.395 +        r = " -R"
   1.396 +
   1.397 +    qprint("Applying %s%s" % (os.path.basename(p), r))
   1.398 +    if options["dry-run"]:
   1.399 +        return ver
   1.400 +
   1.401 +    def cmd(patch, reverse, dry):
   1.402 +        base = "patch -l -p1%s" % reverse
   1.403 +        if dry:
   1.404 +            base += " --dry-run"
   1.405 +
   1.406 +        if p[-4:] == ".bz2":
   1.407 +            pipe = "bzcat %s | %s" % (patch, base)
   1.408 +        elif p[-3:] == ".gz":
   1.409 +            pipe = "zcat %s | %s" % (patch, base)
   1.410 +        else:
   1.411 +            pipe = "%s < %s" % (base, patch)
   1.412 +
   1.413 +        err = os.system(pipe + " > .patchdiag")
   1.414 +        if err:
   1.415 +            sys.stderr.write(open(".patchdiag").read())
   1.416 +        os.unlink(".patchdiag")
   1.417 +        return err
   1.418 +
   1.419 +    err = cmd(p, r, 1)
   1.420 +    if err:
   1.421 +        error("patch %s failed: %d" % (p, err))
   1.422 +        sys.exit(-1)
   1.423 +
   1.424 +    err = cmd(p, r, 0)
   1.425 +    if err:
   1.426 +        error("patch %s failed while it was supposed to apply: %d" % (p, err))
   1.427 +        sys.exit(-1)
   1.428 +
   1.429 +def untar(tarfile):
   1.430 +    old = os.getcwd()
   1.431 +    os.mkdir("ketchup-tmp")
   1.432 +    os.chdir("ketchup-tmp")
   1.433 +
   1.434 +    err = os.system("bzcat %s | tar -xf -" % tarfile)
   1.435 +    if err:
   1.436 +        error("Unpacking failed: ", err)
   1.437 +        sys.exit(-1)
   1.438 +
   1.439 +    err = os.system("mv linux*/* linux*/.[^.]* ..; rmdir linux*")
   1.440 +    if err:
   1.441 +        error("Unpacking failed: ", err)
   1.442 +        sys.exit(-1)
   1.443 +
   1.444 +    os.chdir(old)
   1.445 +    shutil.rmtree("ketchup-tmp")
   1.446 +
   1.447 +def install_nearest(ver):
   1.448 +    t = tree(ver)
   1.449 +    tarballs = glob.glob(archive + "/linux-%s.*.tar.bz2" % t)
   1.450 +    list = []
   1.451 +
   1.452 +    for f in tarballs:
   1.453 +        m = re.match(r'.*/linux-(.*).tar.bz2$', f)
   1.454 +        v = m.group(1)
   1.455 +        d = abs(rev(v) - rev(ver))
   1.456 +        list.append((d, f, v))
   1.457 +    list.sort()
   1.458 +
   1.459 +    if not list or (options["full-tarball"] and list[0][0]):
   1.460 +        f = "linux-%s.tar.bz2" % ver
   1.461 +        url = "%s/v%s/%s" % (kernel_url, t, f)
   1.462 +        f = archive + "/" + f
   1.463 +
   1.464 +        sign = find_info(ver)[3]
   1.465 +        if sign == 1: sign = ".sign"
   1.466 +
   1.467 +        f = trydownload([url], f, sign)
   1.468 +        if not f:
   1.469 +            error("Tarball download failed")
   1.470 +            sys.exit(-1)
   1.471 +
   1.472 +    else:
   1.473 +        f = list[0][1]
   1.474 +        ver = list[0][2]
   1.475 +
   1.476 +    qprint("Unpacking %s" % os.path.basename(f))
   1.477 +    if options["dry-run"]: return ver
   1.478 +    untar(f)
   1.479 +
   1.480 +    return ver
   1.481 +
   1.482 +def find_ver(ver):
   1.483 +    if ver in version_info.keys():
   1.484 +        v = version_info[ver]
   1.485 +        d = v[1]
   1.486 +        if type(d) is type([]):
   1.487 +            d = d[0]
   1.488 +        for n in range(5):
   1.489 +            return v[0](os.path.dirname(d), v[2])
   1.490 +            error('retrying version lookup for %s' % ver)
   1.491 +    else:
   1.492 +        return ver
   1.493 +
   1.494 +def transform(a, b):
   1.495 +    if a == b:
   1.496 +        qprint("Nothing to do!")
   1.497 +        return
   1.498 +    if not a:
   1.499 +        a = install_nearest(base(b))
   1.500 +    t = tree(a)
   1.501 +    if t != tree(b):
   1.502 +        error("Can't patch %s to %s" % (tree(a), tree(b)))
   1.503 +        sys.exit(-1)
   1.504 +    if fork(a):
   1.505 +        apply_patch(a, 1)
   1.506 +        a = prebase(a)
   1.507 +    if prebase(a) != prebase(b):
   1.508 +        if pre(a):
   1.509 +            apply_patch(a, 1)
   1.510 +            a = base(a)
   1.511 +
   1.512 +        if post(a) and post(a) != post(b):
   1.513 +            apply_patch(prebase(a), 1)
   1.514 +
   1.515 +        ra, rb = rev(a), rev(b)
   1.516 +        if ra > rb:
   1.517 +            for r in range(ra, rb, -1):
   1.518 +                apply_patch("%s.%s" % (t, r), -1)
   1.519 +        if ra < rb:
   1.520 +            for r in range(ra + 1, rb + 1):
   1.521 +                apply_patch("%s.%s" % (t, r))
   1.522 +        a = revbase(b)
   1.523 +
   1.524 +        if post(b) and post(a) != post(b):
   1.525 +            apply_patch(prebase(b), 0)
   1.526 +            a = base(b)
   1.527 +
   1.528 +        if pre(b):
   1.529 +            apply_patch(prebase(b))
   1.530 +            a = prebase(b)
   1.531 +
   1.532 +    if fork(b):
   1.533 +        a = apply_patch(b)
   1.534 +
   1.535 +def rename_dir(v):
   1.536 +    """Rename the current directory to linux-v, where v is the function arg"""
   1.537 +    if rename_with_localversion:
   1.538 +        v += get_localversion()
   1.539 +    cwd = os.getcwd()
   1.540 +    basedir = os.path.dirname(cwd)
   1.541 +    newdir = os.path.join(basedir, rename_prefix + v)
   1.542 +    if newdir == cwd:
   1.543 +        return
   1.544 +    if os.access(newdir, os.F_OK):
   1.545 +        error("Cannot rename directory, destination exists: %s", newdir);
   1.546 +        return
   1.547 +    os.rename(cwd, newdir)
   1.548 +    qprint('Current directory renamed to %s' % newdir)
   1.549 +
   1.550 +
   1.551 +# latest lookup function, canonical urls, pattern for lookup function,
   1.552 +#  signature flag, description
   1.553 +version_info = {
   1.554 +    '2.4': (latest_dir,
   1.555 +            kernel_url + "/v2.4" + "/patch-%(base)s.bz2",
   1.556 +            r'patch-(.*?).bz2',
   1.557 +            1, "old stable kernel series"),
   1.558 +    '2.4-pre': (latest_dir,
   1.559 +                kernel_url + "/v2.4" + "/testing/patch-%(prebase)s.bz2",
   1.560 +                r'patch-(.*?).bz2',
   1.561 +                1, "old stable kernel series prereleases"),
   1.562 +    '2.6': (latest_dir,
   1.563 +            kernel_url + "/v2.6" + "/patch-%(prebase)s.bz2",
   1.564 +            r'patch-(.*?).bz2',
   1.565 +            1, "current stable kernel series"),
   1.566 +    '2.6-rc': (latest_dir,
   1.567 +                kernel_url + "/v2.6" + "/testing/patch-%(prebase)s.bz2",
   1.568 +                r'patch-(.*?).bz2',
   1.569 +                1, "current stable kernel series prereleases"),
   1.570 +    '2.6-pre': (latest_dir,
   1.571 +                kernel_url + "/v2.6" + "/testing/patch-%(prebase)s.bz2",
   1.572 +                r'patch-(.*?).bz2',
   1.573 +                1, "current stable kernel series prereleases"),
   1.574 +    '2.6-git': (latest_dir,
   1.575 +                [kernel_url + "/v2.6" + "/snapshots/patch-%(full)s.bz2",
   1.576 +                 kernel_url + "/v2.6" + "/snapshots/old/patch-%(full)s.bz2"],
   1.577 +                r'patch-(.*?).bz2',
   1.578 +                1, "current stable kernel series snapshots"),
   1.579 +    '2.6-bk': (latest_dir,
   1.580 +               [kernel_url + "/v2.6" + "/snapshots/patch-%(full)s.bz2",
   1.581 +                kernel_url + "/v2.6" + "/snapshots/old/patch-%(full)s.bz2"],
   1.582 +               r'patch-(.*?).bz2',
   1.583 +               1, "old stable kernel series snapshots"),
   1.584 +    '2.6-tip': (latest_26_tip, "", "", 1,
   1.585 +                "current stable kernel series tip"),
   1.586 +    '2.6-mm': (latest_mm,
   1.587 +               kernel_url + "/people/akpm/patches/" +
   1.588 +               "%(tree)s/%(prebase)s/%(full)s/%(full)s.bz2", "",
   1.589 +               1, "Andrew Morton's -mm development tree"),
   1.590 +    '2.6-tiny': (latest_dir,
   1.591 +                 "http://www.selenic.com/tiny/%(full)s.patch.bz2",
   1.592 +                 r'(2.6.*?).patch.bz2',
   1.593 +                 1, "Matt Mackall's -tiny tree for small systems"),
   1.594 +    '2.6-mjb': (latest_mjb,
   1.595 +                 kernel_url + "/people/mbligh/%(prebase)s/patch-%(full)s.bz2",
   1.596 +                 r'patch-(2.6.*?).bz2',
   1.597 +                 1, "Martin Bligh's random collection 'o crap"),
   1.598 +    '2.6-rt': (latest_dir,
   1.599 +               ["http://people.redhat.com/mingo/" +
   1.600 +                "realtime-preempt/patch-%(full)s",
   1.601 +                "http://people.redhat.com/mingo/" +
   1.602 +                "realtime-preempt/older/patch-%(full)s"],
   1.603 +               r'patch-(2.6.*?)',
   1.604 +               0, "Ingo Molnar's realtime-preempt kernel"),
   1.605 +    '2.6-ck': (latest_ck,
   1.606 +               ["http://ck.kolivas.org/patches/2.6/" +
   1.607 +                "%(prebase)s/%(full)s/patch-%(full)s.bz2",
   1.608 +                "http://ck.kolivas.org/patches/2.6/pre-releases/" +
   1.609 +                "%(prebase)s/%(full)s/patch-%(full)s.bz2"],
   1.610 +               "", ".sig",
   1.611 +               "Con Kolivas' patches for system responsiveness (desktop)"),
   1.612 +    '2.6-cks': (latest_dir,
   1.613 +                "http://ck.kolivas.org/patches/cks/patch-%(full)s.bz2",
   1.614 +                r'patch-(2.6.*?).bz2', ".sig",
   1.615 +                "Con Kolivas' patches for system responsiveness (server)")
   1.616 +    }
   1.617 +
   1.618 +# Override defaults with ~/.ketchuprc which is just a Python script
   1.619 +rcpath = os.path.expanduser('~/.ketchuprc')
   1.620 +if os.path.isfile(rcpath):
   1.621 +    try:
   1.622 +        execfile(rcpath)
   1.623 +    except Exception, e:
   1.624 +        sys.exit('Failed parsing %s\nError was: %s' % (rcpath, e))
   1.625 +
   1.626 +# Add local trees
   1.627 +for k,v in local_trees.items():
   1.628 +    version_info[k] = v
   1.629 +
   1.630 +# Environment variables override defaults and ketchuprc
   1.631 +kernel_url = os.environ.get("KETCHUP_URL", kernel_url)
   1.632 +archive = os.environ.get("KETCHUP_ARCH", archive)
   1.633 +
   1.634 +# And finally command line overrides everything
   1.635 +if not os.path.exists(wget): wget = ""
   1.636 +if not os.path.exists(gpg): gpg = ""
   1.637 +
   1.638 +options = {}
   1.639 +opts = [
   1.640 +    ('a', 'archive', archive, 'cache directory'),
   1.641 +    ('d', 'directory', '.', 'directory to update'),
   1.642 +    ('f', 'full-tarball', None, 'if unpacking a tarball, download the latest'),
   1.643 +    ('g', 'gpg-path', gpg, 'path for GnuPG'),
   1.644 +    ('G', 'no-gpg', None, 'disable GPG signature verification'),
   1.645 +    ('k', 'kernel-url', kernel_url, 'base url for kernel.org mirror'),
   1.646 +    ('l', 'list-trees', None, 'list supported trees'),
   1.647 +    ('m', 'show-makefile', None, 'output version in makefile <arg>'),
   1.648 +    ('n', 'dry-run', None, 'don\'t download or apply patches'),
   1.649 +    ('p', 'show-previous', None, 'output version previous to <arg>'),
   1.650 +    ('q', 'quiet', None, 'reduce output'),
   1.651 +    ('r', 'rename-directory', None, 'rename updated directory to %s<v>'
   1.652 +     % rename_prefix),
   1.653 +    ('s', 'show-latest', None, 'output the latest version of <arg>'),
   1.654 +    ('u', 'show-url', None, 'output URL for <arg>'),
   1.655 +    ('w', 'wget', wget, 'command to use for wget'),
   1.656 +    ]
   1.657 +
   1.658 +args = fancyopts(sys.argv[1:], opts, options,
   1.659 +                 'ketchup [options] [ver]')
   1.660 +
   1.661 +archive = options["archive"]
   1.662 +kernel_url = options["kernel-url"]
   1.663 +if options["no-gpg"]: options["gpg-path"] = ''
   1.664 +
   1.665 +# Process args
   1.666 +
   1.667 +if not os.path.exists(options["directory"]):
   1.668 +    qprint("Creating target directory", options["directory"])
   1.669 +    os.mkdir(options["directory"])
   1.670 +os.chdir(options["directory"])
   1.671 +
   1.672 +if os.path.isfile(".ketchuprc"):
   1.673 +    try:
   1.674 +        execfile(".ketchuprc")
   1.675 +    except Exception, e:
   1.676 +        sys.exit('Failed parsing .ketchuprc\nError was: %s' % (e))
   1.677 +
   1.678 +if options["list-trees"]:
   1.679 +    l = version_info.keys()
   1.680 +    l.sort()
   1.681 +    for tree in l:
   1.682 +	if version_info[tree][3] == 0:
   1.683 +	   lprint(tree, "(unsigned)")
   1.684 +        else:
   1.685 +	   lprint(tree, "(signed)")
   1.686 +        lprint(" " + version_info[tree][4])
   1.687 +    sys.exit(0)
   1.688 +
   1.689 +if options["show-makefile"] and len(args) < 2:
   1.690 +    if not args:
   1.691 +        lprint(get_ver("Makefile"))
   1.692 +    else:
   1.693 +        lprint(get_ver(args[0]))
   1.694 +    sys.exit(0)
   1.695 +
   1.696 +if len(args) == 0 and default_tree:
   1.697 +    qprint("Using default tree \"%s\"" % (default_tree))
   1.698 +    args.append(default_tree)
   1.699 +
   1.700 +if len(args) != 1:
   1.701 +    error("No version given on command line and no default in configuration")
   1.702 +    sys.exit(-1)
   1.703 +
   1.704 +if options["show-latest"]:
   1.705 +    lprint(find_ver(args[0]))
   1.706 +    sys.exit(0)
   1.707 +
   1.708 +if options["show-url"]:
   1.709 +    lprint(version_urls(find_ver(args[0]))[0])
   1.710 +    sys.exit(0)
   1.711 +
   1.712 +if options["show-previous"]:
   1.713 +    v = find_ver(args[0])
   1.714 +    p = prebase(v)
   1.715 +    if p == v: p = base(v)
   1.716 +    if p == v:
   1.717 +        if rev(v) > 0: p = "%.1f.%s" % (tree(v), rev(v) -1)
   1.718 +        else: p = "unknown"
   1.719 +    lprint(p)
   1.720 +    sys.exit(0)
   1.721 +
   1.722 +if not os.path.exists(options["archive"]):
   1.723 +    qprint("Creating cache directory", options["archive"])
   1.724 +    os.mkdir(options["archive"])
   1.725 +
   1.726 +if precommand and os.system(precommand):
   1.727 +    sys.exit('Precommand "%s" failed!' % precommand)
   1.728 +
   1.729 +try:
   1.730 +    a = get_ver('Makefile')
   1.731 +except:
   1.732 +    a = None
   1.733 +
   1.734 +if not a and os.listdir("."):
   1.735 +    error("Can't find kernel version for non-empty directory")
   1.736 +    sys.exit(-1)
   1.737 +
   1.738 +b = find_ver(args[0])
   1.739 +qprint("%s -> %s" % (a, b))
   1.740 +transform(a, b)
   1.741 +if options["rename-directory"] and not options["dry-run"]:
   1.742 +    rename_dir(b)
   1.743 +
   1.744 +if postcommand and os.system(postcommand):
   1.745 +    sys.exit('Postcommand "%s" failed!' % postcommand)
     2.1 --- a/buildconfigs/src.tarball	Mon Jul 09 11:29:39 2007 +0100
     2.2 +++ b/buildconfigs/src.tarball	Mon Jul 09 11:57:07 2007 +0100
     2.3 @@ -1,8 +1,13 @@
     2.4  XEN_LINUX_MIRROR ?= http://www.kernel.org/pub/linux/kernel/v2.6/
     2.5  XEN_LINUX_TARBALL ?= linux-$(LINUX_VER)-xen.tar.bz2
     2.6  
     2.7 +# Update using ketchup instead of manipulating tarball manually.
     2.8 +XEN_LINUX_TARBALL_KETCHUP ?= n
     2.9 +
    2.10  LINUX_SRCDIR ?= linux-$(LINUX_VER)
    2.11  
    2.12 +KETCHUP ?= buildconfigs/ketchup
    2.13 +
    2.14  vpath linux-%.tar.bz2 $(LINUX_SRC_PATH)
    2.15  
    2.16  # download a pristine Linux kernel tarball if there isn't one in LINUX_SRC_PATH
    2.17 @@ -12,6 +17,11 @@ linux-%.tar.bz2:
    2.18  
    2.19  # XXX create a pristine tree for diff -Nurp convenience
    2.20  
    2.21 +ifeq ($(XEN_LINUX_TARBALL_KETCHUP),y)
    2.22 +%/.valid-src:
    2.23 +	$(KETCHUP) -d $(@D) $(LINUX_VER)
    2.24 +	touch $@ # update timestamp to avoid rebuild
    2.25 +else
    2.26  %/.valid-src: %.tar.bz2
    2.27  	rm -rf tmp-linux-$* $(@D)
    2.28  	mkdir -p tmp-linux-$*
    2.29 @@ -20,3 +30,4 @@ linux-%.tar.bz2:
    2.30  	mv tmp-linux-$*/* $(@D)
    2.31  	@rm -rf tmp-linux-$*
    2.32  	touch $@ # update timestamp to avoid rebuild
    2.33 +endif