Example #1
0
File: lib.py Project: Leopardob/be
def list_pattern(topics):

    project = topics[0]

    be = _extern.load_be(project)
    templates = _extern.load_templates(project)
    inventory = _extern.load_inventory(project)

    # Get item
    try:
        key = be.get("templates", {}).get("key") or "{1}"
        item = _format.item_from_topics(key, topics)
        binding = _format.binding_from_item(inventory, item)

    except KeyError:
        return []

    except IndexError as exc:
        raise IndexError("At least %s topics are required" % str(exc))

    fields = _format.replacement_fields_from_context(context(project))
    binding = _format.binding_from_item(inventory, item)
    pattern = _format.pattern_from_template(templates, binding)

    # 2 arguments, {1}/{2}/{3} -> {1}/{2}
    # 2 arguments, {1}/{2}/assets/{3} -> {1}/{2}/assets
    index_end = pattern.index(str(len(topics)-1)) + 2
    trimmed_pattern = pattern[:index_end]

    # If there aren't any more positional arguments, we're done
    if not re.findall("{[\d]+}", pattern[index_end:]):
        return []

    # Append trail
    # e.g. {1}/{2}/assets
    #             ^^^^^^^
    try:
        index_trail = pattern[index_end:].index("{")
        trail = pattern[index_end:index_end + index_trail - 1]
        trimmed_pattern += trail
    except ValueError:
        pass

    try:
        path = trimmed_pattern.format(*topics, **fields)
    except IndexError:
        raise IndexError("Template for \"%s\" has unordered "
                         "positional arguments: \"%s\"" % (item, pattern))

    if not os.path.isdir(path):
        return []

    items = list()
    for dirname in os.listdir(path):
        if not os.path.isdir(os.path.join(path, dirname)):
            continue

        items.append(dirname)

    return items
Example #2
0
File: cli.py Project: 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)