diff --git a/src/oebuild/app/conf/plugins.yaml b/src/oebuild/app/conf/plugins.yaml index aa2541f736dc7fbd8364e0ca42f504b796d1849c..d81d6dfb3294d52356c6c978cced76adb8fa47db 100644 --- a/src/oebuild/app/conf/plugins.yaml +++ b/src/oebuild/app/conf/plugins.yaml @@ -35,3 +35,9 @@ plugins: - name: toolchain class: Toolchain path: plugins/toolchain/toolchain.py +- name: docker-save + class: DockerSave + path: plugins/docker-save/docker_save.py +- name: samples + class: Samples + path: plugins/samples/samples.py diff --git a/src/oebuild/app/main.py b/src/oebuild/app/main.py index 6975bfc3ac95f737a1729960b80dcb3c0e042ab1..1bd9f8231604e0fce0c664d8cc71cf47818e0206 100644 --- a/src/oebuild/app/main.py +++ b/src/oebuild/app/main.py @@ -21,7 +21,6 @@ import oebuild.const as oebuild_const from oebuild.m_log import logger from oebuild.parse_param import ParseCompileParam from oebuild.configure import Configure -from oebuild.auto_completion import AutoCompletion from oebuild.version import __version__ from oebuild.spec import get_spec, _ExtCommand from oebuild.command import OebuildCommand @@ -98,7 +97,7 @@ class OebuildApp: description='''The openEuler Embedded meta-tool. you can directly run oebuild in oebuild workspace to perform the build, for example: -oebuild qemu-aarch64-ros.yaml +oebuild ''', epilog='''Run "oebuild -h" for help on each .''', add_help=False, oebuild_app=self @@ -301,10 +300,11 @@ class QuickBuild(): ''' xxx ''' - os.chdir(self.build_dir) + os.chdir(os.path.abspath(self.build_dir)) if self.compile_param.bitbake_cmds is None: print("================================================\n\n" - f"please enter {self.build_dir} for next steps!!!\n\n" + "please enter follow directory for next steps!!!\n\n" + f"{os.path.abspath(self.build_dir)}\n\n" "================================================\n") return for bitbake_cmd in self.compile_param.bitbake_cmds: @@ -314,6 +314,12 @@ class QuickBuild(): bitbake_cmd.lstrip("bitbake") ] self.app.run(argv or sys.argv[1:]) + logger.info(""" +====================================================================== +Please enter the building directory according to the command prompt below: + + cd %s +""", os.path.dirname(os.path.abspath(self.build_dir))) def main(argv=None): @@ -323,7 +329,8 @@ def main(argv=None): if not check_user(): return - AutoCompletion().run() + # the auto compiletion will be disabled, when get more good idea and enable it + # AutoCompletion().run() if (len(sys.argv) > 1) and 'yaml' in sys.argv[1]: build = QuickBuild(build_yaml_path=sys.argv[1]) build.run() diff --git a/src/oebuild/app/plugins/bitbake/bitbake.py b/src/oebuild/app/plugins/bitbake/bitbake.py index 6d55155bda0003ed2bde13776d7daf4ef074808e..f24a8ed5addf6722ff11936d5d43d3767dcb5e34 100644 --- a/src/oebuild/app/plugins/bitbake/bitbake.py +++ b/src/oebuild/app/plugins/bitbake/bitbake.py @@ -54,7 +54,12 @@ class Bitbake(OebuildCommand): parser = self._parser(parser_adder, usage=''' - %(prog)s [command] + %(prog)s [command] [--with-docker-image] + --with-docker-image + that is pointed which docker image will be started, and the + docker_param->image will be modified from compile.yaml + the command example like: + oebuild bitbake --with-docker-image=demo:latest ''') parser_adder.add_argument( @@ -79,6 +84,7 @@ class Bitbake(OebuildCommand): sys.exit(0) set_log_to_file() + oe_params, unknown = self._get_oebuild_param(unknown) command = self._get_command(unknow=unknown) if not self.check_support_bitbake(): @@ -92,6 +98,7 @@ class Bitbake(OebuildCommand): compile_param_dict = oebuild_util.read_yaml(self.compile_conf_dir) compile_param: CompileParam = ParseCompileParam.parse_to_obj( compile_param_dict) + compile_param = self._deal_oe_params(oe_params, compile_param) # if has manifest.yaml, init layer repo with it yocto_dir = os.path.join(self.configure.source_dir(), @@ -132,3 +139,31 @@ class Bitbake(OebuildCommand): return None return 'bitbake ' + ' '.join(unknow) + + def _get_oebuild_param(self, unknow: list): + if len(unknow) == 0: + return [], [] + oe_params = [] + new_unknow = [] + for item in unknow: + if item.startswith("--with-docker-image"): + oe_params.append(item) + else: + new_unknow.append(item) + return oe_params, new_unknow + + def _deal_oe_params(self, oe_params, compile_param: CompileParam): + is_modify = False + for item in oe_params: + if item.startswith("--with-docker-image"): + item_split = item.split("=") + if len(item_split) < 2: + logger.error("the format is --with-docker-image=xxx:yyy") + sys.exit(-1) + if compile_param.build_in == oebuild_const.BUILD_IN_DOCKER: + compile_param.docker_param.image = item_split[1] + is_modify = True + if is_modify: + oebuild_util.write_yaml(self.compile_conf_dir, + ParseCompileParam().parse_to_dict(compile_param)) + return compile_param diff --git a/src/oebuild/app/plugins/docker-save/docker_save.py b/src/oebuild/app/plugins/docker-save/docker_save.py new file mode 100644 index 0000000000000000000000000000000000000000..0337dec0257a50d2fcc38959ab8c2785cef3291a --- /dev/null +++ b/src/oebuild/app/plugins/docker-save/docker_save.py @@ -0,0 +1,89 @@ +''' +Copyright (c) 2023 openEuler Embedded +oebuild is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. +''' + +import argparse +import sys +import textwrap +import os + +from docker.errors import APIError + +from oebuild.command import OebuildCommand +from oebuild.configure import Configure +from oebuild.m_log import logger +from oebuild.parse_env import ParseEnv +from oebuild.docker_proxy import DockerProxy + + +class DockerSave(OebuildCommand): + ''' + This class is designed to rapidly generate a customized container image, aiming + to address scenarios where the compilation environment has been specially tailored + but reuse of the container environment is required. + ''' + + help_msg = 'help to save a docker image' + description = textwrap.dedent(''' + This is designed to rapidly generate a customized container image, aiming + to address scenarios where the compilation environment has been specially tailored + but reuse of the container environment is required. + ''') + + def __init__(self): + self.configure = Configure() + self.client = DockerProxy() + super().__init__('docker-save', self.help_msg, self.description) + + def do_add_parser(self, parser_adder) -> argparse.ArgumentParser: + parser = self._parser(parser_adder, + usage=''' + %(prog)s [docker-image] +''') + + # Secondary command + return parser + + def do_run(self, args: argparse.Namespace, unknown=None): + # perpare parse help command + if '-h' in unknown: + unknown[0] = '-h' + self.pre_parse_help(args, unknown) + sys.exit(1) + docker_image = unknown[0] + docker_image_split = docker_image.split(":") + if len(docker_image_split) != 2: + logger.error("the docker image format is repository:tag," + "should be set like openeuler:latest") + sys.exit(-1) + + if not self.configure.is_oebuild_dir(): + logger.error('Your current directory had not finished init') + sys.exit(-1) + + if ".env" not in os.listdir(): + # the command must run based on .env file + logger.error("dcommand need .env to get container id" + "so you must run it in compile directory") + sys.exit(-1) + env_obj = ParseEnv(env_dir=".env") + if not self.client.is_container_exists(env_obj.container.short_id): + logger.error("the container id: %s is not exist in .env") + sys.exit(-1) + + container = self.client.get_container(env_obj.container.short_id) + logger.info("the docker image %s is generatting ...", docker_image) + try: + container.commit(docker_image_split[0], docker_image_split[1]) + except APIError: + logger.error("save %s failed") + sys.exit(-1) + logger.info("the new docker image %s is generated", docker_image) diff --git a/src/oebuild/app/plugins/samples/samples.py b/src/oebuild/app/plugins/samples/samples.py new file mode 100644 index 0000000000000000000000000000000000000000..e897ff8fa145d9364699674a71c0f4131d7b4bd4 --- /dev/null +++ b/src/oebuild/app/plugins/samples/samples.py @@ -0,0 +1,93 @@ +''' +Copyright (c) 2023 openEuler Embedded +oebuild is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. +''' + +import argparse +import sys +import textwrap +import os + +from oebuild.command import OebuildCommand +from oebuild.configure import Configure +from oebuild.m_log import logger + + +class Samples(OebuildCommand): + ''' + The 'samples' command is used to efficiently manage the existing compilation templates in + yocto-meta-openeuler. These templates are located in the yocto-meta-openeuler/.oebuild/samples + directory, and this command allows for rapid implementation of the build process. + ''' + + help_msg = "manage the yocto-meta-openeuler's samples compile files" + description = textwrap.dedent(''' + The 'samples' command is used to efficiently manage the existing compilation templates in + yocto-meta-openeuler. These templates are located in the yocto-meta-openeuler/.oebuild/samples + directory, and this command allows for rapid implementation of the build process. + ''') + + def __init__(self): + self.configure = Configure() + super().__init__('samples', self.help_msg, self.description) + + def do_add_parser(self, parser_adder) -> argparse.ArgumentParser: + parser = self._parser(parser_adder, + usage=''' + %(prog)s [list] +''') + + # Secondary command + return parser + + def do_run(self, args: argparse.Namespace, unknown=None): + # perpare parse help command + if '-h' in unknown: + unknown = ['-h'] + self.pre_parse_help(args, unknown) + sys.exit(0) + if not self.configure.is_oebuild_dir(): + logger.error('Your current directory had not finished init') + sys.exit(-1) + samples = self._get_samples() + if len(unknown) > 0 and 'list' == unknown[0]: + for key, value in samples.items(): + print(f"{key}: {value}") + return + + self.do_exec(samples=samples) + + def _get_samples(self): + list_samples = os.listdir(self.configure.yocto_samples_dir()) + res = {} + for index, sample in enumerate(list_samples): + res[str(index + 1)] = sample + return res + + def do_exec(self, samples: dict): + """ + we let the user select the sample num for next build task + """ + for key, value in samples.items(): + print(f"{key}: {value}") + select_num = "" + while True: + res = input("please select what you want build, enter the num, q for exit: ") + if res not in samples and res != "q": + logger.info("please enter the valid num or q") + continue + if res == "q": + sys.exit(0) + select_num = res + break + sample = samples[select_num] + sample_path = os.path.join(self.configure.yocto_samples_dir(), sample) + + os.system(f"oebuild {sample_path}") diff --git a/src/oebuild/configure.py b/src/oebuild/configure.py index ab916f1381ebb83f814507a26bef8c033dacea43..109f62bde4624dcb2ac5ef6dc0dec990f9b6bca4 100644 --- a/src/oebuild/configure.py +++ b/src/oebuild/configure.py @@ -139,6 +139,13 @@ class Configure: ''' return os.path.join(Configure.source_yocto_dir(), ".oebuild/manifest.yaml") + @staticmethod + def yocto_samples_dir(): + ''' + return .oebuild/samples + ''' + return os.path.join(Configure.source_yocto_dir(), ".oebuild/samples") + @staticmethod def source_poky_dir(): ''' diff --git a/src/oebuild/docker_proxy.py b/src/oebuild/docker_proxy.py index f1a33fe06474b99ed3c44127d8e49186b043581a..1005faed234a7e232dc1919d2d673b56030ab4f6 100644 --- a/src/oebuild/docker_proxy.py +++ b/src/oebuild/docker_proxy.py @@ -45,6 +45,18 @@ class DockerProxy: except ImageNotFound: return False + def get_container_img_id(self, container_id): + ''' + determize if container exists + args: + container_id (str): docker container short_id or id + ''' + try: + container = self._docker.containers.get(container_id=container_id) + return container.image.id + except NotFound: + return None + def is_container_exists(self, container_id): ''' determize if container exists diff --git a/src/oebuild/util.py b/src/oebuild/util.py index a979aac238b6b128bba2a86e9860cffe63656a6b..593f6833d73852f1030f9b74c300948e11221f27 100644 --- a/src/oebuild/util.py +++ b/src/oebuild/util.py @@ -343,10 +343,16 @@ def deal_env_container(env: ParseEnv, docker_param: DockerParam): are inconsistent, you need to create a new container, otherwise directly enable the sleeping container ''' + def check_container_img_eq(container_id, docker_image): + c_mid = docker_proxy.get_container_img_id(container_id=container_id) + d_mid = docker_proxy.get_image(docker_image).id + return c_mid == d_mid + docker_proxy = DockerProxy() if env.container is None \ or env.container.short_id is None \ - or not docker_proxy.is_container_exists(env.container.short_id): + or not docker_proxy.is_container_exists(env.container.short_id) \ + or not check_container_img_eq(env.container.short_id, docker_param.image): # judge which container container: Container = docker_proxy.create_container( image=docker_param.image, diff --git a/src/oebuild/version.py b/src/oebuild/version.py index 69f5bb89500c94fc7442abc6c4e357c35d879f56..efe6fe207b85cd964d21eb6e284e996cdb43ccb6 100644 --- a/src/oebuild/version.py +++ b/src/oebuild/version.py @@ -10,4 +10,4 @@ MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the Mulan PSL v2 for more details. ''' -__version__ = '0.0.45' +__version__ = '0.0.45.21'