Ejemplo n.º 1
0
def write_settings(settings_path, settings, dry_run):
    if dry_run:
        return
    parent_dir = os.path.dirname(settings_path)
    if not os.path.exists(parent_dir):
        makedirs(parent_dir)
    json_dump_file(settings_path, settings, internal=True)
Ejemplo n.º 2
0
 def inner_function(*args, **kwargs):
     # calculate a cache key based on the decorated method signature
     key = u"{}{}{}{}".format(
         re.sub(
             "pluginbase\._internalspace.[^\.]+\.",
             "click_project.plugins.", f.__module__),
         f.__name__,
         args,
         kwargs).encode(u"utf-8")
     # print(key)
     key = hashlib.sha1(key).hexdigest()
     if not os.path.exists(cache_folder):
         makedirs(cache_folder)
     filepath = os.path.join(cache_folder, key)
     # verify that the cached object exists and is less than $seconds old
     if os.path.exists(filepath):
         modified = os.path.getmtime(filepath)
         age_seconds = time.time() - modified
         if expire is None or age_seconds < expire:
             return pickle.load(open(filepath, u"rb"))
     # call the decorated function...
     result = f(*args, **kwargs)
     # ... and save the cached object for next time
     pickle.dump(result, open(filepath, u"wb"))
     return result
Ejemplo n.º 3
0
 def write_settings(self):
     if self.read_only:
         raise click.UsageError(
             "You cannot edit the configuration if the migration is not persisted"
         )
     makedirs(self.location)
     self.write_version()
     return write_settings(self.settings_path, self.settings, self.dry_run)
Ejemplo n.º 4
0
 def write_version(self):
     if self.frozen_during_migration:
         raise click.UsageError(
             "You cannot edit the configuration if the migration is not persisted"
         )
     makedirs(self.location)
     version = self.version
     createfile(self.version_file_name, ensure_unicode(str(version)), internal=True)
Ejemplo n.º 5
0
 def write_settings(self):
     if self.readonly:
         raise click.UsageError(
             f"Cannot write into {self.name}. It is read only.")
     if self.frozen_during_migration:
         raise click.UsageError(
             "You cannot edit the configuration if the migration is not persisted"
         )
     makedirs(self.location)
     self.write_version()
     return write_settings(self.settings_path, self.settings, self.dry_run)
Ejemplo n.º 6
0
def _move(customcommand, profile, force):
    """Move a custom commands"""
    new_location = Path(profile.location) / "bin" / Path(
        customcommand.customcommand_path).name
    if new_location.exists() and not force:
        raise click.UsageError(f"I won't overwrite {new_location},"
                               " unless called with --force")
    makedirs(new_location.parent)
    move(customcommand.customcommand_path, new_location)
    LOGGER.status(
        f"Moved {customcommand.customcommand_path} into {new_location}")
Ejemplo n.º 7
0
def _move(profile_source, plugin, profile_destination, force):
    """Move a custom commands"""
    old_location = Path(profile_source.location) / "plugins" / (plugin + ".py")
    new_location = Path(
        profile_destination.location) / "plugins" / (plugin + ".py")
    if new_location.exists() and not force:
        raise click.UsageError(f"I won't overwrite {new_location},"
                               " unless called with --force")
    makedirs(new_location.parent)
    move(old_location, new_location)
    LOGGER.status(f"Moved {old_location} into {new_location}")
Ejemplo n.º 8
0
 def migrate_settings_to_recipe(settings_level_file, name):
     if open(settings_level_file, "rb").read().decode("utf-8").strip() == "{}":
         return False
     makedirs(recipes_dir + "/" + name)
     enabled = not json.load(open(settings_level_file)).get("_self", {}).get("disabled", False)
     order = json.load(open(settings_level_file)).get("_self", {}).get("order", 100)
     move(settings_level_file, recipes_dir + "/" + name + "/{}.json".format(self.app_name))
     createfile(recipes_dir + "/" + name + "/version.txt", str(self.version + 1))
     createfile(recipes_dir + "/" + name + ".json", json.dumps(
         {
             "enabled": enabled,
             "order": order,
         }
     )
     )
     return True
Ejemplo n.º 9
0
def python(name, open, force, description, body):
    """Create a bash custom command"""
    if not name.endswith(".py"):
        name += ".py"
    script_path = Path(
        config.customcommands.profile.location) / "python" / name
    makedirs(script_path.parent)
    if script_path.exists() and not force:
        raise click.UsageError(f"Won't overwrite {script_path} unless"
                               " explicitly asked so with --force")
    command_name = script_path.name[:-len(".py")]
    script_path.write_text(f"""#!/usr/bin/env python3
# -*- coding:utf-8 -*-

from pathlib import Path

import click

from click_project.decorators import (
    argument,
    flag,
    option,
    command,
    use_settings,
    table_format,
    table_fields,
)
from click_project.lib import (
    TablePrinter,
    call,
)
from click_project.config import config
from click_project.log import get_logger
from click_project.types import DynamicChoice


LOGGER = get_logger(__name__)


@command()
def {command_name}():
    "{description}"
    {body}
""")
    if open:
        click.edit(filename=str(script_path))
Ejemplo n.º 10
0
 def migrate(self, persist=True):
     LOGGER.action("migrate profile in {}".format(self.location))
     if self.dry_run:
         return False
     if os.path.exists(self.backup_location):
         LOGGER.error(
             "{} already exists. Cannot migrate.".format(self.backup_location)
         )
         return False
     makedirs(self.backup_location)
     for name in self.migration_impact:
         if os.path.exists(os.path.join(self.location, name)):
             copy(
                 os.path.join(self.location, name),
                 os.path.join(self.backup_location, name),
             )
     try:
         res = self._migrate(persist)
     except Exception as e:
         import traceback
         LOGGER.error(e)
         LOGGER.develop(traceback.format_exc())
         res = False
     if res:
         rm(self.backup_location)
     else:
         if persist:
             LOGGER.warning(
                 "The migration of {} did not go well,"
                 " Restoring backup from {}".format(
                     self.location,
                     self.backup_location
                 )
             )
         for name in self.migration_impact:
             if os.path.exists(os.path.join(self.backup_location, name)):
                 if os.path.exists(os.path.join(self.location, name)):
                     rm(
                         os.path.join(self.location, name)
                     )
                 copy(
                     os.path.join(self.backup_location, name),
                     os.path.join(self.location, name),
                 )
         rm(self.backup_location)
     return res
Ejemplo n.º 11
0
def create(profile_source, new_name, open, force, body, description):
    """Rename the plugin"""
    script_path = Path(
        profile_source.location) / "plugins" / (new_name + ".py")
    makedirs(script_path.parent)
    if script_path.exists() and not force:
        raise click.UsageError(f"Won't overwrite {script_path} unless"
                               " explicitly asked so with --force")
    script_path.write_text(f"""#!/usr/bin/env python3
# -*- coding:utf-8 -*-

"{description}"

from pathlib import Path

from click_project.config import config


def load_plugin():
    "Put here the entrypoint of the plugin."
    {body}
""")
    if open:
        click.edit(filename=str(script_path))
Ejemplo n.º 12
0
def record_log(output_directory):
    for c in config.slack.conversations.values():
        LOGGER.info("Dumping history of {}".format(c.data["name_fmt"]))
        output_directory_conversation = os.path.join(
            output_directory, c.data["name_fmt"])
        last_record_file = os.path.join(
            output_directory_conversation, ".oldest")
        if os.path.exists(last_record_file):
            with open(last_record_file) as f:
                oldest = f.read()
        else:
            oldest = None
        makedirs(output_directory_conversation)
        with open(os.path.join(
                output_directory_conversation, "messages.json"),
                  "a",
                  encoding="utf-8"
        ) as message_file:
            now = datetime.datetime.now()
            for message in c.history(oldest=oldest):
                message_file.write(json.dumps(message.data))
                message_file.write("\n")
        with open(last_record_file, "w", encoding="utf-8") as f:
            f.write("{}".format(now.strftime("%s")))
Ejemplo n.º 13
0
def install_plugin(profile, force, plugin, login, password, develop, no_deps):
    """Install a plugin"""
    dest_dir = profile.pluginsdir

    def plugin_location(plugin):
        return os.path.join(dest_dir, "{}.py".format(plugin_file_name(plugin)))

    for _plugin in plugin:
        if not force and os.path.exists(plugin_location(_plugin)):
            raise click.UsageError(
                "{} already installed in profile {}."
                " If you really want to install it, use --force or"
                " run plugin uninstall --{} {}".format(_plugin, profile.name,
                                                       profile.name, _plugin))
    for _plugin in plugin:
        if is_local_plugin(_plugin):
            if _plugin.startswith("file://"):
                content = open(_plugin[len("file://"):],
                               "rb").read().decode("utf-8")
                plugin_file = os.path.abspath(_plugin[len("file://"):])
            else:
                content = open(_plugin, "rb").read().decode("utf-8")
                plugin_file = os.path.abspath(_plugin)
            plugin_name = os.path.basename(plugin_file)[:-3]
            plugin_dir = os.path.dirname(plugin_file)
            if os.path.basename(plugin_dir) != "{}_plugins".format(
                    config.app_name):
                raise click.UsageError(
                    "{} does not look like a plugin directory".format(
                        plugin_dir))
            user_name = os.path.basename(os.path.dirname(plugin_dir))
            plugin_name = "{}/{}".format(user_name, plugin_name)
        else:
            content = get_plugin_from_remote(_plugin)
            plugin_name = _plugin

        def install_requirements():
            require_prefix = "# require: "
            requires = [
                line[len(require_prefix):] for line in content.splitlines()
                if line.startswith(require_prefix)
            ]
            for require in requires:
                LOGGER.status("Installing requirement {}".format(require))
                args = ['--upgrade', require]
                if force:
                    args.append("--force-reinstall")
                pip("install", args)
            plugin_require_prefix = "# plugin_require: "
            plugin_requires = [
                line[len(plugin_require_prefix):]
                for line in content.splitlines()
                if line.startswith(plugin_require_prefix)
            ]
            for plugin_require in plugin_requires:
                LOGGER.status(
                    "Installing plugin requirements {}".format(plugin_require))
                install_plugin(
                    profile=profile,
                    force=force,
                    login=login,
                    password=password,
                    plugin=[plugin_require],
                    develop=False,
                    no_deps=no_deps,
                )

        if not no_deps:
            install_requirements()
        LOGGER.status("Installing plugin {} in profile {}".format(
            plugin_name, profile.name))
        location = plugin_location(plugin_name)
        makedirs(os.path.dirname(location))

        if is_local_plugin(_plugin) and develop:
            LOGGER.debug("Installing {} in develop mode".format(plugin_name))
            if force and os.path.exists(location):
                rm(location)
            ln(plugin_file, location)
        else:
            createfile(location, content)
Ejemplo n.º 14
0
def bash(name, open, force, description, body, from_alias, flowdeps,
         source_bash_helpers):
    """Create a bash custom command"""
    if name.endswith(".sh"):
        LOGGER.warning("Removing the extra .sh so that clk won't confuse it"
                       " with a command name.")
        name = name[:len(".sh")]
    script_path = Path(config.customcommands.profile.location) / "bin" / name
    makedirs(script_path.parent)
    if script_path.exists() and not force:
        raise click.UsageError(f"Won't overwrite {script_path} unless"
                               " explicitly asked so with --force")
    options = []
    arguments = []
    flags = []
    remaining = ""
    args = ""

    if from_alias:
        if body:
            body = body + "\n"
        body = body + "\n".join(
            config.main_command.path + " " + " ".join(map(quote, command))
            for command in config.settings["alias"][from_alias]["commands"])
        flowdeps = list(flowdeps) + get_flow_commands_to_run(from_alias)
        alias_cmd = get_command(from_alias)
        if description:
            description = description + "\n"
        description = description + f"Converted from the alias {from_alias}"

        def guess_type(param):
            if type(param.type) == click.Choice:
                return json.dumps(list(param.type.choices))
            elif param.type == int:
                return "int"
            elif param.type == float:
                return "float"
            else:
                return "str"

        for param in alias_cmd.params:
            if type(param) == Option:
                if param.is_flag:
                    flags.append(
                        f"F:{','.join(param.opts)}:{param.help}:{param.default}"
                    )
                    args += f"""
if [ "${{{config.main_command.path.upper()}___{param.name.upper()}}}" == "True" ]
then
    args+=({param.opts[-1]})
fi"""
                else:
                    options.append(
                        f"O:{','.join(param.opts)}:{guess_type(param)}:{param.help}"
                    )
                    args += f"""
if [ -n "${{{config.main_command.path.upper()}___{param.name.upper()}}}" ]
then
    args+=({param.opts[-1]} "${{{config.main_command.path.upper()}___{param.name.upper()}}}")
fi"""
            elif type(param) == Argument:
                if param.nargs == -1:
                    remaining = param.help
                else:
                    arguments.append(
                        f"A:{','.join(param.opts)}:{guess_type(param)}:{param.help}"
                    )
                    args += f"""
args+=("${{{config.main_command.path.upper()}___{param.name.upper()}}}")
"""
        if args:
            args = """# Build the arguments of the last command of the alias
args=()""" + args
            body += ' "${args[@]}"'
        if remaining:
            body += ' "${@}"'

    if flowdeps:
        flowdeps_str = "flowdepends: " + ", ".join(flowdeps) + "\n"
    else:
        flowdeps_str = ""
    if options:
        options_str = "\n".join(options) + "\n"
    else:
        options_str = ""
    if arguments:
        arguments_str = "\n".join(arguments) + "\n"
    else:
        arguments_str = ""
    if flags:
        flags_str = "\n".join(flags) + "\n"
    else:
        flags_str = ""
    if remaining:
        remaining_str = f"N:{remaining}\n"
    else:
        remaining_str = ""

    script_path.write_text(f"""#!/bin/bash -eu

source "${{CLK_INSTALL_LOCATION}}/commands/customcommand/_clk.sh"

clk_usage () {{
    cat<<EOF
$0

{description}
--
{flowdeps_str}{options_str}{flags_str}{arguments_str}{remaining_str}
EOF
}}

clk_help_handler "$@"

{args}
{body}
""")
    chmod(script_path, 0o755)
    if open:
        click.edit(filename=str(script_path))
Ejemplo n.º 15
0
def fork(force, name):
    """Create a brand new project, based on clk that can be used by itself."""
    output = Path(name)
    if output.exists():
        if force:
            rm(output)
        else:
            raise click.UsageError(f"{output} already exist")
    makedirs(output)
    createfile(
        output / "setup.py", f"""#!/usr/bin/env python3
# -*- coding:utf-8 -*-

from setuptools import setup, find_packages

setup(
    name='{name}',
    version="0.0.0",
    packages=find_packages(),
    zip_safe=False,
    install_requires=[
        "click-project",
    ],
    entry_points={{
        'console_scripts':
        [
            '{name}={name}.main:main',
        ]
    }},
)
""")
    package = (output / name)
    makedirs(package)
    createfile(
        package / "main.py", f"""#!/usr/bin/env python3
# -*- coding:utf-8 -*-

from click_project.setup import basic_entry_point, main
from click_project.decorators import command, argument, flag, option


@basic_entry_point(
__name__,
extra_command_packages=["{name}.commands"],
exclude_core_commands=["git-sync"],
)
def {name}(**kwargs):
    pass

if __name__ == "__main__":
    main()
""")
    createfile(package / "__init__.py", f"""#!/usr/bin/env python3""")
    commands = (package / "commands")
    makedirs(commands)
    (commands / "somecommand.py", """#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import click
from click_project.decorators import command, argument, flag, option
from click_project.log import get_logger


LOGGER = get_logger(__name__)


@command()
@argument("some-argument", help="some argument")
@flag("--some-flag/--no-some-flag", help="some flag")
@option("--some-option", help="some option")
def somecommand(some_argument, some_flag, some_option):
    "Some command"
    LOGGER.info(some_argument)
    LOGGER.info(some_flag)
    LOGGER.info(some_option)
""")
    print(f"Now, install {name} with `python3 -m pip install {name}`,"
          f" enable its completion with `{name} completion install`"
          f" and don't forget to have fun")