1# TODO: need a function to get the newest config file older than us from
2# the repo.
3
4import shutil, os
5from autotest_lib.client.bin import utils
6from autotest_lib.client.common_lib import error, kernel_versions
7
8def apply_overrides(orig_file, changes_file, output_file):
9    override = dict()
10
11    # First suck all the changes into a dictionary.
12    input = file(changes_file, 'r')
13    for line in input.readlines():
14        if line.startswith('CONFIG_'):
15            key = line.split('=')[0]
16            override[key] = line;
17        elif line.startswith('# CONFIG_'):
18            key = line.split(' ')[1]
19            override[key] = line;
20    input.close()
21
22    # Now go through the input file, overriding lines where need be
23    input = file(orig_file, 'r')
24    output = file(output_file, 'w')
25    for line in input.readlines():
26        if line.startswith('CONFIG_'):
27            key = line.split('=')[0]
28        elif line.startswith('# CONFIG_'):
29            key = line.split(' ')[1]
30        else:
31            key = None
32        if key and key in override:
33            output.write(override[key])
34        else:
35            output.write(line)
36    input.close()
37    output.close()
38
39
40def diff_configs(old, new):
41    utils.system('diff -u %s %s > %s' % (old, new, new + '.diff'),
42                 ignore_status=True)
43
44
45
46def modules_needed(config):
47    return (utils.grep('CONFIG_MODULES=y', config) and utils.grep('=m', config))
48
49
50def config_by_name(name, set):
51    version = kernel_versions.version_choose_config(name, set[1:])
52    if version:
53        return set[0] + version
54    return None
55
56
57class kernel_config(object):
58    # Build directory must be ready before init'ing config.
59    #
60    # Stages:
61    #       1. Get original config file
62    #       2. Apply overrides
63    #       3. Do 'make oldconfig' to update it to current source code
64    #                  (gets done implicitly during the process)
65    #
66    # You may specifiy the a defconfig within the tree to build,
67    # or a custom config file you want, or None, to get machine's
68    # default config file from the repo.
69
70    build_dir = ''          # the directory we're building in
71    config_dir = ''         # local repository for config_file data
72
73    build_config = ''       # the config file in the build directory
74    orig_config = ''        # the original config file
75    over_config = ''        # config file + overrides
76
77
78    def __init__(self, job, build_dir, config_dir, orig_file,
79                            overrides, defconfig = False, name = None, make = None):
80        self.build_dir = build_dir
81        self.config_dir = config_dir
82
83        #       1. Get original config file
84        self.build_config = build_dir + '/.config'
85        if (orig_file == '' and not defconfig and not make):    # use user default
86            set = job.config_get("kernel.default_config_set")
87            defconf = None
88            if set and name:
89                defconf = config_by_name(name, set)
90            if not defconf:
91                defconf = job.config_get("kernel.default_config")
92            if defconf:
93                orig_file = defconf
94        if (orig_file == '' and not make and defconfig):        # use defconfig
95            make = 'defconfig'
96        if (orig_file == '' and make): # use the config command
97            print "kernel_config: using " + make + " to configure kernel"
98            os.chdir(build_dir)
99            make_return = utils.system('make %s > /dev/null' % make)
100            self.config_record(make)
101            if (make_return):
102                raise error.TestError('make % failed' % make)
103        else:
104            print "kernel_config: using " + orig_file + \
105                                            " to configure kernel"
106            self.orig_config = config_dir + '/config.orig'
107            utils.get_file(orig_file, self.orig_config)
108            self.update_config(self.orig_config, self.orig_config+'.new')
109            diff_configs(self.orig_config, self.orig_config+'.new')
110
111
112        #       2. Apply overrides
113        if overrides:
114            print "kernel_config: using " + overrides + \
115                                            " to re-configure kernel"
116            self.over_config = config_dir + '/config.over'
117            overrides_local = self.over_config + '.changes'
118            utils.get_file(overrides, overrides_local)
119            apply_overrides(self.build_config, overrides_local, self.over_config)
120            self.update_config(self.over_config, self.over_config+'.new')
121            diff_configs(self.over_config, self.over_config+'.new')
122        else:
123            self.over_config = self.orig_config
124
125
126    def update_config(self, old_config, new_config = 'None'):
127        os.chdir(self.build_dir)
128        shutil.copyfile(old_config, self.build_config)
129        utils.system('yes "" | make oldconfig > /dev/null')
130        if new_config:
131            shutil.copyfile(self.build_config, new_config)
132
133    def config_record(self, name):
134        #Copy the current .config file to the config.<name>[.<n>]
135        i = 1
136        to = self.config_dir + '/config.%s' % name
137        while os.path.exists(to):
138            i += 1
139            to = self.config_dir + '/config.%s.%d' % (name,i)
140        shutil.copyfile(self.build_dir + '/.config', to)
141