Esempio n. 1
0
    def run(self, parsed_args):
        """Run the command."""
        lib_name = parsed_args.name
        valid_all_chars = set(string.ascii_lowercase + string.digits + '_')
        valid_first_char = string.ascii_lowercase
        if set(lib_name) - valid_all_chars or not lib_name or lib_name[0] not in valid_first_char:
            raise CommandError(
                "Invalid library name. Must only use lowercase alphanumeric "
                "characters and underscore, starting with alpha.")

        charm_name = get_name_from_metadata()
        if charm_name is None:
            raise CommandError(
                "Cannot find a valid charm name in metadata.yaml. Check you are in a charm "
                "directory with metadata.yaml.")

        # '-' is valid in charm names, but not in a python import
        # mutate the name so the path is a valid import
        importable_charm_name = create_importable_name(charm_name)

        # all libraries born with API version 0
        full_name = 'charms.{}.v0.{}'.format(importable_charm_name, lib_name)
        lib_data = _get_lib_info(full_name=full_name)
        lib_path = lib_data.path
        if lib_path.exists():
            raise CommandError('This library already exists: {}'.format(lib_path))

        store = Store(self.config.charmhub)
        lib_id = store.create_library_id(charm_name, lib_name)

        # create the new library file from the template
        env = get_templates_environment('charmlibs')
        template = env.get_template('new_library.py.j2')
        context = dict(lib_id=lib_id)
        try:
            lib_path.parent.mkdir(parents=True, exist_ok=True)
            lib_path.write_text(template.render(context))
        except OSError as exc:
            raise CommandError(
                "Error writing the library in {}: {!r}.".format(lib_path, exc))

        logger.info("Library %s created with id %s.", full_name, lib_id)
        logger.info("Consider 'git add %s'.", lib_path)
Esempio n. 2
0
    def run(self, args):
        """Execute command's actual functionality."""
        if any(self.config.project.dirpath.iterdir()) and not args.force:
            raise CommandError(
                "{} is not empty (consider using --force to work on nonempty directories)"
                .format(self.config.project.dirpath))
        logger.debug("Using project directory '%s'",
                     self.config.project.dirpath)

        if args.author is None:
            gecos = pwd.getpwuid(os.getuid()).pw_gecos.split(",", 1)[0]
            if not gecos:
                raise CommandError(
                    "Author not given, and nothing in GECOS field")
            logger.debug("Setting author to %r from GECOS field", gecos)
            args.author = gecos

        if not args.name:
            args.name = self.config.project.dirpath.name
            logger.debug("Set project name to '%s'", args.name)

        if not re.match(r"[a-z][a-z0-9-]*[a-z0-9]$", args.name):
            raise CommandError("{} is not a valid charm name".format(
                args.name))

        context = {
            "name": args.name,
            "author": args.author,
            "year": date.today().year,
            "class_name":
            "".join(re.split(r"\W+", args.name.title())) + "Charm",
        }

        env = get_templates_environment("init")

        _todo_rx = re.compile("TODO: (.*)")
        todos = []
        executables = ["run_tests", "src/charm.py"]
        for template_name in env.list_templates():
            if not template_name.endswith(".j2"):
                continue
            template = env.get_template(template_name)
            template_name = template_name[:-3]
            logger.debug("Rendering %s", template_name)
            path = self.config.project.dirpath / template_name
            if path.exists():
                continue
            path.parent.mkdir(parents=True, exist_ok=True)
            with path.open("wt", encoding="utf8") as fh:
                out = template.render(context)
                fh.write(out)
                for todo in _todo_rx.findall(out):
                    todos.append((template_name, todo))
                if template_name in executables:
                    make_executable(fh)
                    logger.debug("  made executable")
        logger.info(
            "Charm operator package file and directory tree initialized.")
        if todos:
            logger.info("TODO:")
            logger.info("")
            w = max(len(i[0]) for i in todos)
            for fn, todo in todos:
                logger.info("%*s: %s", w + 2, fn, todo)
Esempio n. 3
0
    def run(self, args):
        """Execute command's actual functionality."""
        init_dirpath = self.config.project.dirpath
        if not init_dirpath.exists():
            init_dirpath.mkdir(parents=True)
        elif any(init_dirpath.iterdir()) and not args.force:
            tpl = "{!r} is not empty (consider using --force to work on nonempty directories)"
            raise CommandError(tpl.format(str(init_dirpath)))
        emit.trace(f"Using project directory {str(init_dirpath)!r}")

        if args.author is None and pwd is not None:
            args.author = _get_users_full_name_gecos()

        if not args.author:
            raise CommandError(
                "Unable to automatically determine author's name, specify it with --author"
            )

        if not args.name:
            args.name = init_dirpath.name
            emit.trace(f"Set project name to '{args.name}'")

        if not re.match(r"[a-z][a-z0-9-]*[a-z0-9]$", args.name):
            raise CommandError("{} is not a valid charm name".format(
                args.name))

        context = {
            "name": args.name,
            "author": args.author,
            "year": date.today().year,
            "class_name":
            "".join(re.split(r"\W+", args.name.title())) + "Charm",
        }

        env = get_templates_environment("init")

        _todo_rx = re.compile("TODO: (.*)")
        todos = []
        executables = ["run_tests", "src/charm.py"]
        for template_name in env.list_templates():
            if not template_name.endswith(".j2"):
                continue
            template = env.get_template(template_name)
            template_name = template_name[:-3]
            emit.trace(f"Rendering {template_name}")
            path = init_dirpath / template_name
            if path.exists():
                continue
            path.parent.mkdir(parents=True, exist_ok=True)
            with path.open("wt", encoding="utf8") as fh:
                out = template.render(context)
                fh.write(out)
                for todo in _todo_rx.findall(out):
                    todos.append((template_name, todo))
                if template_name in executables and os.name == "posix":
                    make_executable(fh)
                    emit.trace("  made executable")
        emit.message(
            "Charm operator package file and directory tree initialized.")
        if todos:
            emit.message("TODO:")
            emit.message("")
            width = max(len(i[0]) for i in todos) + 2
            for fn, todo in todos:
                emit.message(f"{fn:>{width}s}: {todo}")