#!/usr/bin/python
"""
Program and API used to expand kernel versions, trying to match
them with the URL of the correspondent package on kernel.org or
a mirror. Example:
$ ./kernelexpand.py 3.1
http://www.kernel.org/pub/linux/kernel/v3.x/linux-3.1.tar.bz2
:author: Andy Whitcroft (apw@shadowen.org)
:copyright: IBM 2008
:license: GPL v2
:see: Inspired by kernelexpand by Martin J. Bligh, 2003
"""
try:
import autotest.common as common # pylint: disable=W0611
except ImportError:
import common # pylint: disable=W0611
import re
import sys
import urllib2
from autotest.client.shared.settings import settings
[docs]def get_mappings_2x():
KERNEL_BASE_URL = settings.get_value('CLIENT', 'kernel_mirror', default='')
GITWEB_BASE_URL = settings.get_value('CLIENT', 'kernel_gitweb', default='')
STABLE_GITWEB_BASE_URL = settings.get_value('CLIENT', 'stable_kernel_gitweb', default='')
MAPPINGS_2X = [
[r'^\d+\.\d+$', '', True,
map(lambda x: x + 'v%(major)s/linux-%(full)s.tar.bz2', KERNEL_BASE_URL.split()) +
map(lambda x: x + ';a=snapshot;h=refs/tags/v%(full)s;sf=tgz', GITWEB_BASE_URL.split())
],
[r'^\d+\.\d+\.\d+$', '', True,
map(lambda x: x + 'v%(major)s/linux-%(full)s.tar.bz2', KERNEL_BASE_URL.split()) +
map(lambda x: x + ';a=snapshot;h=refs/tags/v%(full)s;sf=tgz', GITWEB_BASE_URL.split())
],
[r'^\d+\.\d+\.\d+\.\d+$', '', True,
map(lambda x: x + 'v%(major)s/linux-%(full)s.tar.bz2', KERNEL_BASE_URL.split()) +
map(lambda x: x + ';a=snapshot;h=refs/tags/v%(full)s;sf=tgz', STABLE_GITWEB_BASE_URL.split())
],
[r'-rc\d+$', '%(minor-prev)s', True,
map(lambda x: x + 'v%(major)s/testing/v%(minor)s/linux-%(full)s.tar.bz2', KERNEL_BASE_URL.split()) +
map(lambda x: x + 'v%(major)s/testing/linux-%(full)s.tar.bz2', KERNEL_BASE_URL.split()) +
map(lambda x: x + ';a=snapshot;h=refs/tags/v%(full)s;sf=tgz', GITWEB_BASE_URL.split())
],
[r'-(git|bk)\d+$', '%(base)s', False,
map(lambda x: x + 'v%(major)s/snapshots/old/patch-%(full)s.bz2', KERNEL_BASE_URL.split()) +
map(lambda x: x + 'v%(major)s/snapshots/patch-%(full)s.bz2', KERNEL_BASE_URL.split())
],
[r'-mm\d+$', '%(base)s', False,
map(lambda x: x + 'people/akpm/patches/' + '%(major)s/%(base)s/%(full)s/%(full)s.bz2', KERNEL_BASE_URL.split())
],
[r'-mjb\d+$', '%(base)s', False,
map(lambda x: x + 'people/mbligh/%(base)s/patch-%(full)s.bz2', KERNEL_BASE_URL.split())
],
[r'[a-f0-9]{7,40}$', '', True,
map(lambda x: x + ';a=snapshot;h=%(full)s;sf=tgz', GITWEB_BASE_URL.split()) +
map(lambda x: x + ';a=snapshot;h=%(full)s;sf=tgz', STABLE_GITWEB_BASE_URL.split())
]
]
return MAPPINGS_2X
[docs]def get_mappings_post_2x():
KERNEL_BASE_URL = settings.get_value('CLIENT', 'kernel_mirror', default='')
GITWEB_BASE_URL = settings.get_value('CLIENT', 'kernel_gitweb', default='')
STABLE_GITWEB_BASE_URL = settings.get_value('CLIENT', 'stable_kernel_gitweb', default='')
MAPPINGS_POST_2X = [
[r'^\d+\.\d+$', '', True,
map(lambda x: x + 'v%(major)s/linux-%(full)s.tar.bz2', KERNEL_BASE_URL.split()) +
map(lambda x: x + 'v%(major)s/linux-%(full)s.tar.xz', KERNEL_BASE_URL.split()) +
map(lambda x: x + ';a=snapshot;h=refs/tags/v%(full)s;sf=tgz', GITWEB_BASE_URL.split())
],
[r'^\d+\.\d+\.\d+$', '', True,
map(lambda x: x + 'v%(major)s/linux-%(full)s.tar.bz2', KERNEL_BASE_URL.split()) +
map(lambda x: x + 'v%(major)s/linux-%(full)s.tar.xz', KERNEL_BASE_URL.split()) +
map(lambda x: x + ';a=snapshot;h=refs/tags/v%(full)s;sf=tgz', STABLE_GITWEB_BASE_URL.split())
],
[r'-rc\d+$', '', True,
map(lambda x: x + 'v%(major)s/testing/linux-%(full)s.tar.bz2', KERNEL_BASE_URL.split()) +
map(lambda x: x + 'v%(major)s/testing/linux-%(full)s.tar.xz', KERNEL_BASE_URL.split()) +
map(lambda x: x + ';a=snapshot;h=refs/tags/v%(full)s;sf=tgz', GITWEB_BASE_URL.split())
],
[r'[a-f0-9]{7,40}$', '', True,
map(lambda x: x + ';a=snapshot;h=%(full)s;sf=tgz', GITWEB_BASE_URL.split()) +
map(lambda x: x + ';a=snapshot;h=%(full)s;sf=tgz', STABLE_GITWEB_BASE_URL.split())
]
]
return MAPPINGS_POST_2X
[docs]def decompose_kernel_2x_once(kernel):
"""
Generate the parameters for the patches (2.X version):
full => full kernel name
base => all but the matches suffix
minor => 2.n.m
major => 2.n
minor-prev => 2.n.m-1
:param kernel: String representing a kernel version to be expanded.
"""
for mapping in get_mappings_2x():
(suffix, becomes, is_full, patch_templates) = mapping
params = {}
match = re.search(r'^(.*)' + suffix, kernel)
if not match:
continue
params['full'] = kernel
params['base'] = match.group(1)
match = re.search(r'^((\d+\.\d+)\.(\d+))', kernel)
if not match:
raise NameError("Unable to determine major/minor version for "
"kernel %s" % kernel)
params['minor'] = match.group(1)
params['major'] = match.group(2)
params['minor-prev'] = match.group(2) + '.%d' % (int(match.group(3)) - 1)
# Build the new kernel and patch list.
new_kernel = becomes % params
patch_list = []
for template in patch_templates:
patch_list.append(template % params)
return (is_full, new_kernel, patch_list)
return (True, kernel, None)
[docs]def decompose_kernel_post_2x_once(kernel):
"""
Generate the parameters for the patches (post 2.X version):
full => full kernel name
base => all but the matches suffix
minor => o.n.m
major => o.n
minor-prev => o.n.m-1
:param kernel: String representing a kernel version to be expanded.
"""
for mapping in get_mappings_post_2x():
(suffix, becomes, is_full, patch_templates) = mapping
params = {}
match = re.search(r'^(.*)' + suffix, kernel)
if not match:
continue
params['full'] = kernel
params['base'] = match.group(1)
major = ''
match = re.search(r'^((\d+\.\d+)\.(\d+))', kernel)
if not match:
match = re.search(r'^(\d+\.\d+)', kernel)
if not match:
match = re.search(r'^([a-f0-9]{7,40})', kernel)
if not match:
raise NameError("Unable to determine major/minor version for "
"kernel %s" % kernel)
else:
params['minor'] = 0
major = match.group(1)
params['minor-prev'] = match.group(1)
else:
params['minor'] = match.group(1)
major = match.group(1)
params['minor-prev'] = match.group(2) + '.%d' % (int(match.group(3)) - 1)
# Starting with kernels 3.x, we have folders named '3.x' on kernel.org
first_number = major.split('.')[0]
params['major'] = '%s.x' % first_number
# It makes no sense a 3.1.1-rc1 version, for example
if re.search(r'-rc\d+$', params['full']) and params['minor'] != 0:
continue
# Build the new kernel and patch list.
new_kernel = becomes % params
patch_list = []
for template in patch_templates:
patch_list.append(template % params)
return (is_full, new_kernel, patch_list)
return (True, kernel, None)
[docs]def decompose_kernel(kernel):
match = re.search(r'^(\d+\.\d+)', kernel)
if not match:
match = re.search(r'^([a-f0-9]{7,40})', kernel)
if not match:
raise NameError("Unable to determine major/minor version for "
"kernel %s" % kernel)
else:
decompose_func = decompose_kernel_post_2x_once
else:
if int(match.group(1).split('.')[0]) == 2:
decompose_func = decompose_kernel_2x_once
elif int(match.group(1).split('.')[0]) > 2:
decompose_func = decompose_kernel_post_2x_once
kernel_patches = []
done = False
while not done:
(done, kernel, patch_list) = decompose_func(kernel)
if patch_list:
kernel_patches.insert(0, patch_list)
if not len(kernel_patches):
doc_url = 'https://github.com/autotest/autotest/wiki/KernelSpecification'
raise NameError("Kernel '%s' not found. "
"Check %s for kernel spec docs." %
(kernel, doc_url))
return kernel_patches
# Look for and add potential mirrors.
[docs]def mirror_kernel_components(mirrors, components):
new_components = []
for component in components:
new_patches = []
for mirror in mirrors:
(prefix, local) = mirror
for patch in component:
if patch.startswith(prefix):
new_patch = local + patch[len(prefix):]
new_patches.append(new_patch)
for patch in component:
new_patches.append(patch)
new_components.append(new_patches)
return new_components
[docs]def url_accessible(url):
try:
u = urllib2.urlopen(url)
u.close()
return True
except urllib2.HTTPError:
return False
[docs]def select_kernel_components(components):
new_components = []
for component in components:
new_patches = []
for patch in component:
if url_accessible(patch):
new_patches.append(patch)
break
new_components.append(new_patches)
return new_components
[docs]def expand_classic(kernel, mirrors):
components = decompose_kernel(kernel)
if mirrors:
components = mirror_kernel_components(mirrors, components)
components = select_kernel_components(components)
patches = []
for component in components:
patches.append(component[0])
return patches
if __name__ == '__main__':
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-m", "--mirror", type="string", dest="mirror",
action="append", nargs=2, help="mirror prefix")
parser.add_option("-v", "--no-validate", dest="validate",
action="store_false", default=True, help="prune invalid entries")
def usage():
parser.print_help()
sys.exit(1)
options, args = parser.parse_args()
# Check for a kernel version
if len(args) != 1:
usage()
kernel = args[0]
mirrors = options.mirror
try:
components = decompose_kernel(kernel)
except NameError, e:
sys.stderr.write(e.args[0] + "\n")
sys.exit(1)
if mirrors:
components = mirror_kernel_components(mirrors, components)
if options.validate:
components = select_kernel_components(components)
# Dump them out
for component in components:
if component:
print " ".join(component)