From 3bc0c976a909cb42e1ef8e90c2a8a3ec220bfad9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Apr 2013 14:12:55 +0200 Subject: [PATCH] add ckmake back under devel/ dir Signed-off-by: Johannes Berg --- devel/ckmake | 393 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 393 insertions(+) create mode 100644 devel/ckmake diff --git a/devel/ckmake b/devel/ckmake new file mode 100644 index 000000000000..cd9741aed9a3 --- /dev/null +++ b/devel/ckmake @@ -0,0 +1,393 @@ +#!/usr/bin/env python + +# ncurses Linux kernel cross kernel compilation utility + +# Copyright (C) 2012 Luis R. Rodriguez +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. + +import locale +import curses +import time +import os +import re +import random +import tempfile +import subprocess +import sys +import signal + +from Queue import * +from threading import Thread, Lock +from shutil import copytree, ignore_patterns, rmtree, copyfileobj +from time import sleep + +releases_processed = [] +releases_baking = [] +processed_lock = Lock() +baking_lock = Lock() +my_cwd = os.getcwd() +ckmake_return = 0 + +tmp_path = my_cwd + "/.tmp.ckmake" +ckmake_log = my_cwd + "/ckmake.log" +ckmake_report = my_cwd + "/ckmake-report.log" + +home = os.getenv("HOME") +ksrc = home + "/" + "compat-ksrc" +modules = ksrc + "/lib/modules" + +def clean(): + if os.path.exists(tmp_path): + rmtree(tmp_path) + +def get_processed_rel(i): + "Because... list.pop(i) didn't work to keep order..." + processed_lock.acquire() + for rel in releases_processed: + if (rel['idx'] == i): + processed_lock.release() + return rel + processed_lock.release() + + baking_lock.acquire() + for rel in releases_baking: + if (rel['idx'] == i): + releases_baking.remove(rel) + baking_lock.release() + return rel + baking_lock.release() + +def get_status_name(status): + if (status == 0): + return 'OK' + elif (status == 130): + return 'TERM' + elif (status == 1234): + return 'INIT' + elif (status == -2): + return 'TERM' + else: + return 'FAIL' + +def get_stat_pos(status): + if (status == 0): + return 34 + elif (status == 130): + return 33 + elif (status == 1234): + return 33 + elif (status == -2): + return 33 + else: + return 33 + +def get_status_color(status): + if (status == 0): + return curses.color_pair(1) + elif (status == 130): + return curses.color_pair(2) + elif (status == 1234): + return curses.color_pair(2) + elif (status == -2): + return curses.color_pair(2) + else: + return curses.color_pair(3) + +def print_report(): + os.system("clear") + sys.stdout.write("\n\n\n") + sys.stdout.write("== ckmake-report.log ==\n\n") + report = open(ckmake_report, 'r+') + copyfileobj(report, sys.stdout) + report.close() + +def process_logs(): + os.system('clear') + log = open(ckmake_log, 'w+') + report = open(ckmake_report, 'w+') + for i in range(0, len(releases_processed)): + rel = get_processed_rel(i) + rel_log = open(rel['log'], 'r+') + log.write(rel_log.read()) + status = get_status_name(rel['status']) + rel_report = "%-4s%-20s[ %s ]\n" % \ + ( rel['idx']+1, rel['version'], status) + report.write(rel_report) + if (rel['status'] != 0 and + rel['status'] != 2): + ckmake_return = -1 + report.close() + log.close() + print_report() + +def process_kernel(num, kset): + while True: + rel = kset.queue.get() + work_dir = tmp_path + '/' + rel['version'] + copytree(my_cwd, \ + work_dir, \ + ignore=ignore_patterns('\.git*', '.tmp*', ".git")) + build = '%s/build/' % rel['full_path'] + jobs = ' -j%d ' % kset.build_jobs + make_args = 'KLIB=%(build)s KLIB_BUILD=%(build)s' % \ + { "build": build } + log_file = work_dir + '/' + 'ckmake.n.log' + rel['log'] = log_file + # XXX: figure out how to properly address logging + # without this nasty ass hack. + log = ' > %(log)s 2>&1' % { "log": log_file } + nice = 'ionice -c 3 nice -n 20 ' + cmd = nice + 'make ' + jobs + make_args + log + + my_env = os.environ.copy() + my_env["KCFLAGS"] = "-Wno-unused-but-set-variable" + + kset.baking(rel) + + p = subprocess.Popen([cmd], + env = my_env, + cwd = work_dir, + stdout=None, + stderr=None, + shell=True) + p.wait() + + kset.update_status(rel, p.returncode) + kset.queue.task_done() + kset.completed(rel) + +def cpu_info_build_jobs(): + if not os.path.exists('/proc/cpuinfo'): + return 1 + f = open('/proc/cpuinfo', 'r') + max_cpus = 1 + for line in f: + m = re.match(r"(?Pprocessor\s*:)\s*" \ + "(?P\d+)", + line) + if not m: + continue + proc_specs = m.groupdict() + if (proc_specs['NUM'] > max_cpus): + max_cpus = proc_specs['NUM'] + return int(max_cpus) + 1 + +def kill_curses(): + curses.endwin() + sys.stdout = os.fdopen(0, 'w', 0) + +def sig_handler(signal, frame): + kill_curses() + process_logs() + clean() + sys.exit(-2) + +def get_rel_spec(rel): + if ("rc" in rel): + m = re.match(r"v*(?P\d+)\.+" \ + "(?P\d+)[.]+" \ + "(?P\d+)[-]+" \ + "\d+rc(?P\d+)\-*", + rel) + else: + m = re.match(r"v*(?P\d+)\.+" \ + "(?P\d+)[.]+" \ + "(?P\d+)[-]+" \ + "(?P\d+)\-*", + rel) + if (not m): + return m + rel_specs = m.groupdict() + return rel_specs + +def krel_same_base(new_rel, rel): + if (int(new_rel['ver']) != int(rel['ver'])): + return False + if (int(new_rel['pat']) != int(rel['pat'])): + return False + if (int(new_rel['ver']) == 3): + return True + if (int(new_rel['ver']) != 2): + return False + if (int(new_rel['sub']) == int(rel['sub'])): + return True + return False + +def krel_base_update(new_rel, rel): + if (not krel_same_base(new_rel, rel)): + return False + if (int(new_rel['sub']) > int(rel['sub'])): + return True + if (int(new_rel['sub']) < int(rel['sub'])): + return False + + # Too lazy to deal with 2.x kernels, + if (not new_rel['is_rc']): + return False + + if (int(new_rel['ext']) <= int(rel['ext'])): + return False + return True + +def krel_base_smaller(new_rel, rel): + if (not krel_same_base(new_rel, rel)): + return False + if (int(new_rel['sub']) > int(rel['sub'])): + return False + if (int(new_rel['sub']) < int(rel['sub'])): + return True + return False + +class kernel_set(): + def __init__(self, stdscr): + self.queue = Queue() + self.releases = [] + self.stdscr = stdscr + self.lock = Lock() + signal.signal(signal.SIGINT, sig_handler) + self.build_jobs = cpu_info_build_jobs() + if (curses.has_colors()): + curses.init_pair(1, + curses.COLOR_GREEN, + curses.COLOR_BLACK) + curses.init_pair(2, + curses.COLOR_CYAN, + curses.COLOR_BLACK) + curses.init_pair(3, + curses.COLOR_RED, + curses.COLOR_BLACK) + curses.init_pair(4, + curses.COLOR_BLUE, + curses.COLOR_BLACK) + def baking(self, rel): + baking_lock.acquire() + releases_baking.append(rel) + baking_lock.release() + def completed(self, rel): + processed_lock.acquire() + releases_processed.insert(rel['idx'], rel) + processed_lock.release() + def set_locale(self): + locale.setlocale(locale.LC_ALL, '') + code = locale.getpreferredencoding() + def refresh(self): + self.lock.acquire() + self.stdscr.refresh() + self.lock.release() + def evaluate_new_rel(self, new_rel): + for rel in self.releases: + if (krel_base_update(new_rel, rel)): + new_rel['idx'] = rel['idx'] + self.releases.remove(rel) + break + if (krel_base_smaller(new_rel, rel)): + return + self.releases.insert(new_rel['idx'], new_rel) + def parse_releases(self): + for dirname, dirnames, filenames in os.walk(modules): + dirnames.sort() + for subdirname in dirnames: + specifics = get_rel_spec(subdirname) + if (not specifics): + continue + rc = False + + ver = specifics['VERSION'] + '.' + \ + specifics['PATCHLEVEL'] + + if ("rc" in subdirname): + rc = True + ver = ver + '-rc' + specifics['EXTRAVERSION'] + else: + ver = ver + '.' + specifics['SUBLEVEL'] + + rel = dict(idx=len(self.releases), + name=subdirname, + full_path=dirname + '/' + + subdirname, + version=ver, + is_rc = rc, + ver=specifics['VERSION'], + pat=specifics['PATCHLEVEL'], + sub=specifics['SUBLEVEL'], + ext=specifics['EXTRAVERSION'], + processed=False, + log='', + status=1234) + self.evaluate_new_rel(rel) + self.refresh() + def setup_screen(self): + for i in range(0, len(self.releases)): + rel = self.releases[i] + self.lock.acquire() + self.stdscr.addstr(rel['idx'], 0, + "%-4d" % (rel['idx']+1)) + if (curses.has_colors()): + self.stdscr.addstr(rel['idx'], 5, + "%-20s" % (rel['version']), + curses.color_pair(4)) + else: + self.stdscr.addstr(rel['idx'], 0, + "%-20s" % (rel['version'])) + self.stdscr.addstr(rel['idx'], 30, "[ ]") + self.stdscr.refresh() + self.lock.release() + def create_threads(self): + for rel in self.releases: + th = Thread(target=process_kernel, args=(0, self)) + th.setDaemon(True) + th.start() + def kick_threads(self): + for rel in self.releases: + self.queue.put(rel) + sleep(1) + def wait_threads(self): + self.queue.join() + def update_status(self, rel, status): + self.lock.acquire() + stat_name = get_status_name(status) + stat_pos = get_stat_pos(status) + if (curses.has_colors()): + stat_color = get_status_color(status) + self.stdscr.addstr(rel['idx'], stat_pos, stat_name, + get_status_color(status)) + else: + self.stdscr.addstr(rel['idx'], stat_pos, stat_name) + rel['processed'] = True + rel['status'] = status + self.stdscr.refresh() + self.lock.release() + +def main(stdscr): + kset = kernel_set(stdscr) + + kset.set_locale() + kset.parse_releases() + kset.setup_screen() + kset.create_threads() + kset.kick_threads() + kset.wait_threads() + kset.refresh() + +if __name__ == "__main__": + if not os.path.exists(modules): + print "%s does not exist" % (modules) + sys.exit(1) + if not os.path.exists(my_cwd + '/Makefile'): + print "%s does not exist" % (my_cwd + '/Makefile') + sys.exit(1) + if os.path.exists(ckmake_log): + os.remove(ckmake_log) + if os.path.exists(ckmake_report): + os.remove(ckmake_report) + if os.path.exists(tmp_path): + rmtree(tmp_path) + os.makedirs(tmp_path) + curses.wrapper(main) + kill_curses() + process_logs() + clean() + sys.exit(ckmake_return) -- 2.30.2