Exemplo n.º 1
0
Arquivo: cli.py Projeto: Leopardob/be
def activate():
    """Enter into an environment with support for tab-completion

    This command drops you into a subshell, similar to the one
    generated via `be in ...`, except no topic is present and
    instead it enables tab-completion for supported shells.

    See documentation for further information.
    https://github.com/mottosso/be/wiki/cli

    """

    parent = lib.parent()
    cmd = lib.cmd(parent)

    # Store reference to calling shell
    context = lib.context()
    context["BE_SHELL"] = parent

    if lib.platform() == "unix":
        context["BE_TABCOMPLETION"] = os.path.join(
            os.path.dirname(__file__), "_autocomplete.sh").replace("\\", "/")

    context.pop("BE_ACTIVE", None)

    sys.exit(subprocess.call(cmd, env=context))
Exemplo n.º 2
0
Arquivo: cli.py Projeto: Leopardob/be
def in_(ctx, topics, yes, as_, enter):
    """Set the current topics to `topics`

    Environment:
        BE_PROJECT: First topic
        BE_CWD: Current `be` working directory
        BE_TOPICS: Arguments to `in`
        BE_DEVELOPMENTDIR: Absolute path to current development directory
        BE_PROJECTROOT: Absolute path to current project
        BE_PROJECTSROOT: Absolute path to where projects are located
        BE_ACTIVE: 0 or 1, indicates an active be environment
        BE_USER: Current user, overridden with `--as`
        BE_SCRIPT: User-supplied shell script
        BE_PYTHON: User-supplied python script
        BE_ENTER: 0 or 1 depending on whether the topic was entered
        BE_GITHUB_API_TOKEN: Optional GitHub API token
        BE_ENVIRONMENT: Space-separated list of user-added
            environment variables
        BE_TEMPDIR: Directory in which temporary files are stored
        BE_PRESETSDIR: Directory in which presets are searched
        BE_ALIASDIR: Directory in which aliases are written
        BE_BINDING: Binding between template and item in inventory

    \b
    Usage:
        $ be in project topics

    """

    topics = map(str, topics)  # They enter as unicode

    if self.isactive():
        lib.echo("ERROR: Exit current project first")
        sys.exit(lib.USER_ERROR)

    # Determine topic syntax
    if len(topics[0].split("/")) == 3:
        topic_syntax = lib.FIXED
        project = topics[0].split("/")[0]
    else:
        topic_syntax = lib.POSITIONAL
        project = topics[0]

    project_dir = _format.project_dir(_extern.cwd(), project)
    if not os.path.exists(project_dir):
        lib.echo("Project \"%s\" not found. " % project)
        lib.echo("\nAvailable:")
        ctx.invoke(ls)
        sys.exit(lib.USER_ERROR)

    # Boot up
    context = lib.context(project)

    be = _extern.load_be(project)
    templates = _extern.load_templates(project)
    inventory = _extern.load_inventory(project)
    context.update({
        "BE_PROJECT": project,
        "BE_USER": str(as_),
        "BE_ENTER": "1" if enter else "",
        "BE_TOPICS": " ".join(topics)
    })

    # Remap topic syntax, for backwards compatibility
    # In cases where the topic is entered in a way that
    # differs from the template, remap topic to template.
    if any(re.findall("{\d+}", pattern) for pattern in templates.values()):
        template_syntax = lib.POSITIONAL
    else:
        template_syntax = lib.FIXED

    if topic_syntax & lib.POSITIONAL and not template_syntax & lib.POSITIONAL:
        topics = ["/".join(topics)]
    if topic_syntax & lib.FIXED and not template_syntax & lib.FIXED:
        topics[:] = topics[0].split("/")

    try:
        key = be.get("templates", {}).get("key") or "{1}"
        item = _format.item_from_topics(key, topics)
        binding = _format.binding_from_item(inventory, item)
        context["BE_BINDING"] = binding
    except IndexError as exc:
        lib.echo("At least %s topics are required" % str(exc))
        sys.exit(lib.USER_ERROR)

    except KeyError as exc:
        lib.echo("\"%s\" not found" % item)
        if exc.bindings:
            lib.echo("\nAvailable:")
            for item_ in sorted(exc.bindings,
                                key=lambda a: (exc.bindings[a], a)):
                lib.echo("- %s (%s)" % (item_, exc.bindings[item_]))
        sys.exit(lib.USER_ERROR)

    # Finally, determine a development directory
    # based on the template-, not topic-syntax.
    if template_syntax & lib.POSITIONAL:
        try:
            development_dir = _format.pos_development_directory(
                templates=templates,
                inventory=inventory,
                context=context,
                topics=topics,
                user=as_,
                item=item)
        except KeyError as exc:
            lib.echo("\"%s\" not found" % item)
            if exc.bindings:
                lib.echo("\nAvailable:")
                for item_ in sorted(exc.bindings,
                                    key=lambda a: (exc.bindings[a], a)):
                    lib.echo("- %s (%s)" % (item_, exc.bindings[item_]))
            sys.exit(lib.USER_ERROR)

    else:  # FIXED topic_syntax
        development_dir = _format.fixed_development_directory(
            templates,
            inventory,
            topics,
            as_)

    context["BE_DEVELOPMENTDIR"] = development_dir

    tempdir = (tempfile.mkdtemp()
               if not os.environ.get("BE_TEMPDIR")
               else os.environ["BE_TEMPDIR"])
    context["BE_TEMPDIR"] = tempdir

    # Should it be entered?
    if enter and not os.path.exists(development_dir):
        create = False
        if yes:
            create = True
        else:
            sys.stdout.write("No development directory found. Create? [Y/n]: ")
            if raw_input().lower() in ("", "y", "yes"):
                create = True
        if create:
            ctx.invoke(mkdir, dir=development_dir)
        else:
            sys.stdout.write("Cancelled")
            sys.exit(lib.NORMAL)

    # Parse be.yaml
    if "script" in be:
        context["BE_SCRIPT"] = _extern.write_script(
            be["script"], tempdir)

    if "python" in be:
        script = "\n".join(be["python"])
        context["BE_PYTHON"] = script
        try:
            exec script in {"__name__": __name__}
        except Exception as e:
            lib.echo("ERROR: %s" % e)

    invalids = [v for v in context.values() if not isinstance(v, str)]
    assert all(isinstance(v, str) for v in context.values()), invalids

    # Create aliases
    aliases_dir = _extern.write_aliases(
        be.get("alias", {}), tempdir)

    context["PATH"] = (aliases_dir
                       + os.pathsep
                       + context.get("PATH", ""))
    context["BE_ALIASDIR"] = aliases_dir

    # Parse redirects
    _format.parse_redirect(
        be.get("redirect", {}), topics, context)

    # Override inherited context
    # with that coming from be.yaml.
    if "environment" in be:
        parsed = _format.parse_environment(
            fields=be["environment"],
            context=context,
            topics=topics)
        context["BE_ENVIRONMENT"] = " ".join(parsed.keys())
        context.update(parsed)

    if "BE_TESTING" in context:
        os.chdir(development_dir)
        os.environ.update(context)
    else:
        parent = lib.parent()
        cmd = lib.cmd(parent)

        # Store reference to calling shell
        context["BE_SHELL"] = parent

        try:
            sys.exit(subprocess.call(cmd, env=context))
        finally:
            import shutil
            shutil.rmtree(tempdir)