diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..d5c0c99 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.5.1 diff --git a/a8f18bb0-3d1d-4ebb-b47c-5438cd203719.o b/a8f18bb0-3d1d-4ebb-b47c-5438cd203719.o new file mode 100644 index 0000000..8692c05 Binary files /dev/null and b/a8f18bb0-3d1d-4ebb-b47c-5438cd203719.o differ diff --git a/kbuilder/cli/bootstrap.py b/kbuilder/cli/bootstrap.py index 7248f88..09d2c23 100644 --- a/kbuilder/cli/bootstrap.py +++ b/kbuilder/cli/bootstrap.py @@ -6,5 +6,16 @@ from cement.core import handler from kbuilder.cli.controllers.base import KbuilderBaseController +import os + +from cement.core import hook +from kbuilder.core.kernel import Kernel + +def locate_kernel(app): + kernel = Kernel(Kernel.find_root(os.getcwd())) + print("kernel located: " + kernel.name) + app.kernel = kernel + def load(app): handler.register(KbuilderBaseController) + hook.register('pre_kernel_compile', locate_kernel) diff --git a/kbuilder/cli/controllers/base.py b/kbuilder/cli/controllers/base.py index c165415..633d40b 100644 --- a/kbuilder/cli/controllers/base.py +++ b/kbuilder/cli/controllers/base.py @@ -2,6 +2,10 @@ from cement.core.controller import CementBaseController, expose from kbuilder.core import kbuilder +from kbuilder.core import gcc +from kbuilder.cli.main import app +import os +from unipath import Path VERSION = '0.1.0' @@ -31,6 +35,21 @@ def default(self): """Build all targets """ kbuilder.main() + @expose(help="select a toolchain to use") + def select(self): + """Build all targets.""" + toolchain_dir = app.config.get('sublime-flounder', 'toolchain_dir') + toolchain = gcc.select_one(gcc.scandir(toolchain_dir)) + root_dir = Path(app.config.get('sublime-flounder', 'root_dir')) + root_dir.child('.kbuilder_cur_toolchain').write_file(toolchain.name) + + + @expose(help="Show the toolchain selected") + def show(self): + """Build all targets.""" + root_dir = Path(app.config.get('sublime-flounder', 'root_dir')) + print(root_dir.child('.kbuilder_cur_toolchain').read_file()) + # If using an output handler such as 'mustache', you could also # render a data dictionary using a template. For example: # diff --git a/kbuilder/cli/hooks/kernel.py b/kbuilder/cli/hooks/kernel.py new file mode 100644 index 0000000..3e45d96 --- /dev/null +++ b/kbuilder/cli/hooks/kernel.py @@ -0,0 +1,10 @@ +# Kernel related hooks +import os + +from cement.core import hook +from cement.core.kernel import Kernel + +def locate_kernel(app): + kernel = Kernel.find_root(os.getcwd()) + print("kernel located: " + kernel.name) + app.kernel = kernel diff --git a/kbuilder/cli/main.py b/kbuilder/cli/main.py index 5dfc2a1..1e11175 100755 --- a/kbuilder/cli/main.py +++ b/kbuilder/cli/main.py @@ -3,6 +3,7 @@ from cement.core.foundation import CementApp from cement.utils.misc import init_defaults from cement.core.exc import FrameworkError, CaughtSignal +from cement.core import hook from kbuilder.core import exc # Application default. Should update config/kbuilder.conf to reflect any @@ -33,6 +34,14 @@ class Meta: # Internal templates (ship with application code) template_module = 'kbuilder.cli.templates' + def setup(self): + # always run core setup first + super(KbuilderApp, self).setup() + + # define application hooks here + self.hook.define('pre_kernel_compile') + + class KbuilderTestApp(KbuilderApp): diff --git a/kbuilder/core/kbuild_image.py b/kbuilder/core/kbuild_image.py new file mode 100644 index 0000000..86612c2 --- /dev/null +++ b/kbuilder/core/kbuild_image.py @@ -0,0 +1,16 @@ +"""Provide an enumeration for kbuild images. Each architecture has + a kbuild image associated with it. This module helps to link + architures with their respective kbuild image. + """ + +from enum import Enum + +from kbuilder.core.arch import Arch + + +class Kbuild_Image(Enum): + """Provide an enumeration for kbuild images.""" + + Arch.arm = 'zImage' + Arch.arm64 = 'Image.gz-dtb' + Arch.x86 = 'bzImage' diff --git a/kbuilder/core/kernel.py b/kbuilder/core/kernel.py index 609a243..379251c 100644 --- a/kbuilder/core/kernel.py +++ b/kbuilder/core/kernel.py @@ -164,6 +164,19 @@ def build_kbuild_image(self, toolchain: Toolchain, except CalledProcessError: logging.exception( alert('{kernel} failed to compile'.format( - kernel = full_version))) + kernel = full_version))) print('the build log is located at ' + highlight(build_log)) sys.exit(1) + + def build_kbuild_images(self, toolchains: Iterable[Toolchain], + build_log_dir: str=None) -> Tuple[Path, str]: + """Build multiple kbuild images the kernel. + + Return the path of the absolute path of kbuild image if the build is + successful. + Keyword arguments: + toolchains -- the toolchain to use in building the kernel + build_log_dir -- the directory of the build log file + """ + for toolchain in toolchains: + yield self.build(toolchain, build_log_dir) diff --git a/kbuilder/core/kernel_android.py b/kbuilder/core/kernel_android.py new file mode 100644 index 0000000..3c0e454 --- /dev/null +++ b/kbuilder/core/kernel_android.py @@ -0,0 +1,157 @@ +# Copyright (C) 2016 Dela Anthonio +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +"""Provide an interface for android kernels.""" + +import os +from typing import Iterable, Tuple +import shutil +from subprocess import check_call + +from cached_property import cached_property +from unipath import Path + +from kbuilder.core.arch import Arch, UnsupportedArch +from kbuilder.core.gcc import Toolchain +from kbuilder.core.kernel import Kernel +import kbuilder.core.make as mk + + +class AndroidKernel(Kernel): + """Provide an interface for android kernels""" + + def __init__(self, root: str, arch: Arch, *, + defconfig: str='defconfig') -> None: + """Initialze a new Kernel. + + Keyword arguments: + root -- the root directory of the kernel + defconfig -- the defconfig file to use in building the kernel. + """ + Kernel.__init__(root) + self.version = self._find_kernel_version() + self.version_numbers = self.version[-5:] + self._defconfig = defconfig + self._arch = arch + self._kbuild_image = "TODO" + + @property + def defconfig(self): + """The default configuration file of the kernel.""" + return self._defconfig + + @cached_property + def version(self): + return self._find_kernel_version() + + @cached_property + def version_numbers(self): + """The kernel version in MAJOR.MINOR.PATCH format.""" + return self._find_kernel_version()[:-5] + + @cached_property + def kbuild_image(self): + """The path to the compressed kernel image.""" + return self.kbuild_image_abs_path(self.arch, self.kbuild_image) + + def _find_kernel_version(self) -> str: + """Return what the version of the kernel is.""" + with self: + output = mk.make_output('kernelrelease').rstrip() + lines = output.split('\n') + kernelrelease = lines[-1] + return kernelrelease[8:] + + def _find_kbuild_image_name(self): + if self.arch == Arch.arm: + return 'zImage' + elif self.arch == Arch.arm64: + return 'Image.gz-dtb' + elif self.arch == Arch.x86: + return 'bzImage' + else: + raise UnsupportedArch + + def release_version(self, extra_version: str=None) -> str: + """Get the kernel version with the toolchain name appended. + + Arguments: + extension -- the extension to add to this. + """ + if extra_version: + return '{0.version}-{1}'.format(self, extra_version) + else: + return self.version + + def make_defconfig(self) -> None: + """Make the default configuration file.""" + mk.make(self.defconfig) + + def build_kbuild_image(self, *, toolchain: Toolchain, + build_log_dir: str=None) -> Tuple[Path, str]: + """Build the kernel kbuild. + + Return the path of the absolute path of kbuild image if the build is + successful. + Keyword arguments: + toolchain -- the toolchain to use in building the kernel + defconfig -- the default configuration file (default '') + build_log_dir -- the directory of the build log file + """ + kernel_release_version = self.release_version(toolchain.name) + Path(build_log_dir).mkdir() + build_log = Path(build_log_dir, kernel_release_version + '-log.txt') + + print('compiling {0.version} with {1.name}'.format(self, toolchain)) + output = mk.make_output('all') + build_log.write_file(output) + return self.kbuild_image, kernel_release_version + + def build_kbuild_images(self, toolchains: Iterable[Toolchain], + build_log_dir: str=None) -> Tuple[Path, str]: + """Build multiple kbuild images the kernel. + + Return the path of the absolute path of kbuild image if the build is + successful. + Keyword arguments: + toolchain -- the toolchain to use in building the kernel + defconfig -- the default configuration file (default '') + build_log_dir -- the directory of the build log file + """ + for toolchain in toolchains: + yield self.build(toolchain, build_log_dir) + + def make_boot_img(self, name: str, ramdisk: str='ramdisk.img'): + """Create a boot.img file that can be install via fastboot. + + Keyword arguments: + name -- the name of the output file + kbuild_image -- the kernel image to include in the boot.img file + ramdisk -- the ramdisk image to include in the boot.img file + """ + args = '--output {} --kernel {} --ramdisk {}'.format(name, + self.kbuild_image, + ramdisk) + check_call('mkbootimg ' + args, shell=True) + + def zip_ota_package(self, name: str, base_dir: str=os.getcwd()) -> str: + """Create a zip package that can be installed via recovery. + + Return the path to the zip file created + Keyword arguments: + name -- the name of the zip file to create + base_dir -- the directory whose contents should be zipped (default cwd) + """ + return shutil.make_archive(name, 'zip', base_dir)