|
16 | 16 | import email.header |
17 | 17 | import email.parser |
18 | 18 | import logging |
19 | | -import multiprocessing |
20 | 19 | import os |
21 | 20 | import re |
22 | | -import shlex |
23 | 21 | import shutil |
24 | 22 | import subprocess |
25 | | -import sys |
26 | | -import io |
27 | | -import time |
28 | | -from threading import Timer |
29 | 23 | import requests |
30 | 24 |
|
31 | 25 |
|
@@ -436,193 +430,3 @@ def bisect_iter(self, bad): |
436 | 430 | logging.info(line) |
437 | 431 |
|
438 | 432 | return (ret, binfo) |
439 | | - |
440 | | - |
441 | | -class KernelBuilder(object): |
442 | | - def __init__(self, source_dir, basecfg, cfgtype=None, |
443 | | - extra_make_args=None, enable_debuginfo=False): |
444 | | - self.source_dir = source_dir |
445 | | - self.basecfg = basecfg |
446 | | - self.cfgtype = cfgtype if cfgtype is not None else "olddefconfig" |
447 | | - self._ready = 0 |
448 | | - self.buildlog = "%s/build.log" % self.source_dir |
449 | | - self.make_argv_base = ["make", "-C", self.source_dir] |
450 | | - self.enable_debuginfo = enable_debuginfo |
451 | | - |
452 | | - # Split the extra make arguments provided by the user |
453 | | - if extra_make_args: |
454 | | - self.extra_make_args = shlex.split(extra_make_args) |
455 | | - else: |
456 | | - self.extra_make_args = [] |
457 | | - |
458 | | - try: |
459 | | - os.unlink(self.buildlog) |
460 | | - except OSError: |
461 | | - pass |
462 | | - |
463 | | - logging.info("basecfg: %s", self.basecfg) |
464 | | - logging.info("cfgtype: %s", self.cfgtype) |
465 | | - |
466 | | - def prepare(self, clean=True): |
467 | | - if (clean): |
468 | | - args = self.make_argv_base + ["mrproper"] |
469 | | - logging.info("cleaning up tree: %s", args) |
470 | | - subprocess.check_call(args) |
471 | | - |
472 | | - shutil.copyfile(self.basecfg, "%s/.config" % self.source_dir) |
473 | | - |
474 | | - # NOTE(mhayden): Building kernels with debuginfo can increase the |
475 | | - # final kernel tarball size by 3-4x and can increase build time |
476 | | - # slightly. Debug symbols are really only needed for deep diagnosis |
477 | | - # of kernel issues on a specific system. This is why debuginfo is |
478 | | - # disabled by default. |
479 | | - if not self.enable_debuginfo: |
480 | | - args = ["%s/scripts/config" % self.source_dir, |
481 | | - "--file", self.get_cfgpath(), |
482 | | - "--disable", "debug_info"] |
483 | | - logging.info("disabling debuginfo: %s", args) |
484 | | - subprocess.check_call(args) |
485 | | - |
486 | | - args = self.make_argv_base + [self.cfgtype] |
487 | | - logging.info("prepare config: %s", args) |
488 | | - subprocess.check_call(args) |
489 | | - self._ready = 1 |
490 | | - |
491 | | - def get_cfgpath(self): |
492 | | - return "%s/.config" % self.source_dir |
493 | | - |
494 | | - def getrelease(self): |
495 | | - krelease = None |
496 | | - if not self._ready: |
497 | | - self.prepare(False) |
498 | | - |
499 | | - args = self.make_argv_base + ["kernelrelease"] |
500 | | - mk = subprocess.Popen(args, stdout=subprocess.PIPE) |
501 | | - (stdout, _) = mk.communicate() |
502 | | - for line in stdout.split("\n"): |
503 | | - m = re.match(r'^\d+\.\d+\.\d+.*$', line) |
504 | | - if m: |
505 | | - krelease = m.group() |
506 | | - break |
507 | | - |
508 | | - if krelease is None: |
509 | | - raise Exception("Failed to find kernel release in stdout") |
510 | | - |
511 | | - return krelease |
512 | | - |
513 | | - def mktgz(self, clean=True, timeout=60 * 60 * 12): |
514 | | - """ |
515 | | - Build kernel and modules, after that, pack everything into a tarball. |
516 | | -
|
517 | | - Args: |
518 | | - clean: If it is True, run the `mrproper` target before build. |
519 | | - timeout: Max time in seconds will wait for build. |
520 | | - Returns: |
521 | | - The full path of the tarball generated. |
522 | | - Raises: |
523 | | - CommandTimeoutError: When building kernel takes longer than the |
524 | | - specified timeout. |
525 | | - CalledProcessError: When a command returns an exit code different |
526 | | - than zero. |
527 | | - ParsingError: When can not find the tarball path in stdout. |
528 | | - IOError: When tarball file doesn't exist. |
529 | | - """ |
530 | | - fpath = None |
531 | | - stdout_list = [] |
532 | | - self.prepare(clean) |
533 | | - |
534 | | - # Set up the arguments and options for the kernel build |
535 | | - targz_pkg_argv = [ |
536 | | - "INSTALL_MOD_STRIP=1", |
537 | | - "-j%d" % multiprocessing.cpu_count(), |
538 | | - "targz-pkg" |
539 | | - ] |
540 | | - kernel_build_argv = ( |
541 | | - self.make_argv_base |
542 | | - + targz_pkg_argv |
543 | | - + self.extra_make_args |
544 | | - ) |
545 | | - |
546 | | - logging.info("building kernel: %s", kernel_build_argv) |
547 | | - |
548 | | - with io.open(self.buildlog, 'wb') as writer, \ |
549 | | - io.open(self.buildlog, 'rb') as reader: |
550 | | - make = subprocess.Popen(kernel_build_argv, |
551 | | - stdout=writer, |
552 | | - stderr=subprocess.STDOUT) |
553 | | - make_timedout = [] |
554 | | - |
555 | | - def stop_process(proc): |
556 | | - """ |
557 | | - Terminate the process with SIGTERM and flag it as timed out. |
558 | | - """ |
559 | | - if proc.poll() is None: |
560 | | - proc.terminate() |
561 | | - make_timedout.append(True) |
562 | | - timer = Timer(timeout, stop_process, [make]) |
563 | | - timer.setDaemon(True) |
564 | | - timer.start() |
565 | | - try: |
566 | | - while make.poll() is None: |
567 | | - self.append_and_log2stdout(reader.readlines(), stdout_list) |
568 | | - time.sleep(1) |
569 | | - self.append_and_log2stdout(reader.readlines(), stdout_list) |
570 | | - finally: |
571 | | - timer.cancel() |
572 | | - if make_timedout: |
573 | | - raise CommandTimeoutError( |
574 | | - "'{}' was taking too long".format( |
575 | | - ' '.join(kernel_build_argv) |
576 | | - ) |
577 | | - ) |
578 | | - if make.returncode != 0: |
579 | | - raise subprocess.CalledProcessError( |
580 | | - make.returncode, |
581 | | - ' '.join(kernel_build_argv) |
582 | | - ) |
583 | | - |
584 | | - match = re.search("^Tarball successfully created in (.*)$", |
585 | | - ''.join(stdout_list), re.MULTILINE) |
586 | | - if match: |
587 | | - fpath = os.path.realpath( |
588 | | - os.path.join( |
589 | | - self.source_dir, |
590 | | - match.group(1) |
591 | | - ) |
592 | | - ) |
593 | | - else: |
594 | | - raise ParsingError('Failed to find tgz path in stdout') |
595 | | - |
596 | | - if not os.path.isfile(fpath): |
597 | | - raise IOError("Built kernel tarball {} not found".format(fpath)) |
598 | | - |
599 | | - return fpath |
600 | | - |
601 | | - @staticmethod |
602 | | - def append_and_log2stdout(lines, full_log): |
603 | | - """ |
604 | | - Append `lines` into `full_log` and show `lines` on stdout. |
605 | | -
|
606 | | - Args: |
607 | | - lines: list of strings. |
608 | | - full_log: list where `lines` members are appended. |
609 | | - """ |
610 | | - full_log.extend(lines) |
611 | | - sys.stdout.write(''.join(lines)) |
612 | | - sys.stdout.flush() |
613 | | - |
614 | | - |
615 | | -class CommandTimeoutError(Exception): |
616 | | - """ |
617 | | - Exception raised when a timeout occurs on a process which has had timeouts |
618 | | - enabled. The accompanying value is a string whose value is the command |
619 | | - launched plus a small explanation. |
620 | | - """ |
621 | | - |
622 | | - |
623 | | -class ParsingError(Exception): |
624 | | - """ |
625 | | - Exception raised when a regex does not match and it is impossible to |
626 | | - continue. The accompanying value is a string which explains what it can not |
627 | | - find. |
628 | | - """ |
0 commit comments