Beispiel #1
0
def msg(message, *args, **kwargs):
    newline = kwargs.get('newline', True)
    st_text = ""
    if _stacktrace:
        st_text = process_stacktrace(2)
    if newline:
        cprint("@*b{%s==>} %s" % (st_text, cescape(message)))
    else:
        cwrite("@*b{%s==>} %s" % (st_text, cescape(message)))
    for arg in args:
        print(indent + str(arg))
Beispiel #2
0
def msg(message, *args, **kwargs):
    newline = kwargs.get('newline', True)
    st_text = ""
    if _stacktrace:
        st_text = process_stacktrace(2)
    if newline:
        cprint("@*b{%s==>} %s" % (st_text, cescape(message)))
    else:
        cwrite("@*b{%s==>} %s" % (st_text, cescape(message)))
    for arg in args:
        print(indent + str(arg))
Beispiel #3
0
def info(message, *args, **kwargs):
    format = kwargs.get('format', '*b')
    stream = kwargs.get('stream', sys.stderr)
    wrap = kwargs.get('wrap', False)
    break_long_words = kwargs.get('break_long_words', False)
    st_countback = kwargs.get('countback', 3)

    reported_by = kwargs.get('reported_by')
    if reported_by is not None:
        message += ' (reported by {0})'.format(reported_by)

    st_text = ""
    if _stacktrace:
        st_text = process_stacktrace(st_countback)
    cprint("@%s{%s==>} %s%s" %
           (format, st_text, get_timestamp(), cescape(str(message))),
           stream=stream)
    for arg in args:
        if wrap:
            lines = textwrap.wrap(str(arg),
                                  initial_indent=indent,
                                  subsequent_indent=indent,
                                  break_long_words=break_long_words)
            for line in lines:
                stream.write(line + '\n')
        else:
            stream.write(indent + str(arg) + '\n')
Beispiel #4
0
def info(parser, args):
    pkg = spack.repo.get(args.package)

    # Output core package information
    header = section_title(
        '{0}:   '
    ).format(pkg.build_system_class) + pkg.name
    color.cprint(header)

    color.cprint('')
    color.cprint(section_title('Description:'))
    if pkg.__doc__:
        color.cprint(color.cescape(pkg.format_doc(indent=4)))
    else:
        color.cprint("    None")

    color.cprint(section_title('Homepage: ') + pkg.homepage)

    # Now output optional information in expected order
    sections = [
        (args.all or args.maintainers, print_maintainers),
        (args.all or args.detectable, print_detectable),
        (args.all or args.tags, print_tags),
        (args.all or not args.no_versions, print_versions),
        (args.all or not args.no_variants, print_variants),
        (args.all or args.phases, print_phases),
        (args.all or not args.no_dependencies, print_dependencies),
        (args.all or args.virtuals, print_virtuals),
        (args.all or args.tests, print_tests),
    ]
    for print_it, func in sections:
        if print_it:
            func(pkg)

    color.cprint('')
Beispiel #5
0
def info(message, *args, **kwargs):
    if isinstance(message, Exception):
        message = "%s: %s" % (message.__class__.__name__, str(message))

    format = kwargs.get('format', '*b')
    stream = kwargs.get('stream', sys.stdout)
    wrap = kwargs.get('wrap', False)
    break_long_words = kwargs.get('break_long_words', False)
    st_countback = kwargs.get('countback', 3)

    st_text = ""
    if _stacktrace:
        st_text = process_stacktrace(st_countback)
    cprint("@%s{%s==>} %s%s" % (
        format, st_text, get_timestamp(), cescape(six.text_type(message))
    ), stream=stream)
    for arg in args:
        if wrap:
            lines = textwrap.wrap(
                six.text_type(arg), initial_indent=indent,
                subsequent_indent=indent, break_long_words=break_long_words)
            for line in lines:
                stream.write(line + '\n')
        else:
            stream.write(indent + six.text_type(arg) + '\n')
Beispiel #6
0
def msg(message, *args, **kwargs):
    if not msg_enabled():
        return

    newline = kwargs.get('newline', True)
    st_text = ""
    if _stacktrace:
        st_text = process_stacktrace(2)
    if newline:
        cprint("@*b{%s==>} %s%s" %
               (st_text, get_timestamp(), cescape(message)))
    else:
        cwrite("@*b{%s==>} %s%s" %
               (st_text, get_timestamp(), cescape(message)))
    for arg in args:
        print(indent + str(arg))
Beispiel #7
0
def print_versions(pkg):
    """output versions"""

    color.cprint('')
    color.cprint(section_title('Preferred version:  '))

    if not pkg.versions:
        color.cprint(version('    None'))
        color.cprint('')
        color.cprint(section_title('Safe versions:  '))
        color.cprint(version('    None'))
        color.cprint('')
        color.cprint(section_title('Deprecated versions:  '))
        color.cprint(version('    None'))
    else:
        pad = padder(pkg.versions, 4)

        preferred = preferred_version(pkg)
        url = ''
        if pkg.has_code:
            url = fs.for_package_version(pkg, preferred)

        line = version('    {0}'.format(pad(preferred))) + color.cescape(url)
        color.cprint(line)

        safe = []
        deprecated = []
        for v in reversed(sorted(pkg.versions)):
            if pkg.has_code:
                url = fs.for_package_version(pkg, v)
            if pkg.versions[v].get('deprecated', False):
                deprecated.append((v, url))
            else:
                safe.append((v, url))

        for title, vers in [('Safe', safe), ('Deprecated', deprecated)]:
            color.cprint('')
            color.cprint(section_title('{0} versions:  '.format(title)))
            if not vers:
                color.cprint(version('    None'))
                continue

            for v, url in vers:
                line = version('    {0}'.format(pad(v))) + color.cescape(url)
                color.cprint(line)
Beispiel #8
0
def print_variants(pkg):
    """output variants"""

    color.cprint('')
    color.cprint(section_title('Variants:'))

    formatter = VariantFormatter(pkg.variants)
    for line in formatter.lines:
        color.cprint(color.cescape(line))
Beispiel #9
0
def msg(message, *args, **kwargs):
    if not msg_enabled():
        return

    if isinstance(message, Exception):
        message = "%s: %s" % (message.__class__.__name__, str(message))

    newline = kwargs.get('newline', True)
    st_text = ""
    if _stacktrace:
        st_text = process_stacktrace(2)
    if newline:
        cprint("@*b{%s==>} %s%s" % (
            st_text, get_timestamp(), cescape(message)))
    else:
        cwrite("@*b{%s==>} %s%s" % (
            st_text, get_timestamp(), cescape(message)))
    for arg in args:
        print(indent + six.text_type(arg))
Beispiel #10
0
def info(message, *args, **kwargs):
    format = kwargs.get('format', '*b')
    stream = kwargs.get('stream', sys.stdout)
    wrap = kwargs.get('wrap', False)
    break_long_words = kwargs.get('break_long_words', False)
    st_countback = kwargs.get('countback', 3)

    st_text = ""
    if _stacktrace:
        st_text = process_stacktrace(st_countback)
    cprint("@%s{%s==>} %s" % (format, st_text, cescape(str(message))),
           stream=stream)
    for arg in args:
        if wrap:
            lines = textwrap.wrap(
                str(arg), initial_indent=indent, subsequent_indent=indent,
                break_long_words=break_long_words)
            for line in lines:
                stream.write(line + '\n')
        else:
            stream.write(indent + str(arg) + '\n')
Beispiel #11
0
def info(message, *args, **kwargs):
    format = kwargs.get('format', '*b')
    stream = kwargs.get('stream', sys.stdout)
    wrap = kwargs.get('wrap', False)
    break_long_words = kwargs.get('break_long_words', False)
    st_countback = kwargs.get('countback', 3)

    st_text = ""
    if _stacktrace:
        st_text = process_stacktrace(st_countback)
    cprint("@%s{%s==>} %s" % (format, st_text, cescape(str(message))),
           stream=stream)
    for arg in args:
        if wrap:
            lines = textwrap.wrap(
                str(arg), initial_indent=indent, subsequent_indent=indent,
                break_long_words=break_long_words)
            for line in lines:
                stream.write(line + '\n')
        else:
            stream.write(indent + str(arg) + '\n')
Beispiel #12
0
def print_text_info(pkg):
    """Print out a plain text description of a package."""

    header = section_title(
        '{0}:   '
    ).format(pkg.build_system_class) + pkg.name
    color.cprint(header)

    color.cprint('')
    color.cprint(section_title('Description:'))
    if pkg.__doc__:
        color.cprint(color.cescape(pkg.format_doc(indent=4)))
    else:
        color.cprint("    None")

    color.cprint(section_title('Homepage: ') + pkg.homepage)

    if len(pkg.maintainers) > 0:
        mnt = " ".join(['@@' + m for m in pkg.maintainers])
        color.cprint('')
        color.cprint(section_title('Maintainers: ') + mnt)

    color.cprint('')
    color.cprint(section_title("Tags: "))
    if hasattr(pkg, 'tags'):
        tags = sorted(pkg.tags)
        colify(tags, indent=4)
    else:
        color.cprint("    None")

    color.cprint('')
    color.cprint(section_title('Preferred version:  '))

    if not pkg.versions:
        color.cprint(version('    None'))
        color.cprint('')
        color.cprint(section_title('Safe versions:  '))
        color.cprint(version('    None'))
    else:
        pad = padder(pkg.versions, 4)

        # Here we sort first on the fact that a version is marked
        # as preferred in the package, then on the fact that the
        # version is not develop, then lexicographically
        key_fn = lambda v: (pkg.versions[v].get('preferred', False),
                            not v.isdevelop(),
                            v)
        preferred = sorted(pkg.versions, key=key_fn).pop()

        f = fs.for_package_version(pkg, preferred)
        line = version('    {0}'.format(pad(preferred))) + color.cescape(f)
        color.cprint(line)
        color.cprint('')
        color.cprint(section_title('Safe versions:  '))

        for v in reversed(sorted(pkg.versions)):
            f = fs.for_package_version(pkg, v)
            line = version('    {0}'.format(pad(v))) + color.cescape(f)
            color.cprint(line)

    color.cprint('')
    color.cprint(section_title('Variants:'))

    formatter = VariantFormatter(pkg.variants)
    for line in formatter.lines:
        color.cprint(line)

    color.cprint('')
    color.cprint(section_title('Installation Phases:'))
    phase_str = ''
    for phase in pkg.phases:
        phase_str += "    {0}".format(phase)
    color.cprint(phase_str)

    for deptype in ('build', 'link', 'run'):
        color.cprint('')
        color.cprint(section_title('%s Dependencies:' % deptype.capitalize()))
        deps = sorted(pkg.dependencies_of_type(deptype))
        if deps:
            colify(deps, indent=4)
        else:
            color.cprint('    None')

    color.cprint('')
    color.cprint(section_title('Virtual Packages: '))
    if pkg.provided:
        inverse_map = {}
        for spec, whens in pkg.provided.items():
            for when in whens:
                if when not in inverse_map:
                    inverse_map[when] = set()
                inverse_map[when].add(spec)
        for when, specs in reversed(sorted(inverse_map.items())):
            line = "    %s provides %s" % (
                when.colorized(), ', '.join(s.colorized() for s in specs)
            )
            print(line)

    else:
        color.cprint("    None")

    color.cprint('')
Beispiel #13
0
def color_url(path, **kwargs):
    """Color the parts of the url according to Spack's parsing.

    Colors are:
       | Cyan: The version found by :func:`parse_version_offset`.
       | Red:  The name found by :func:`parse_name_offset`.

       | Green:   Instances of version string from :func:`substitute_version`.
       | Magenta: Instances of the name (protected from substitution).

    Args:
        path (str): The filename or URL for the package
        errors (bool): Append parse errors at end of string.
        subs (bool): Color substitutions as well as parsed name/version.
    """
    # Allow URLs containing @ and }
    path = cescape(path)

    errors = kwargs.get('errors', False)
    subs   = kwargs.get('subs', False)

    (name, ns, nl, noffs,
     ver,  vs, vl, voffs) = substitution_offsets(path)

    nends = [no + nl - 1 for no in noffs]
    vends = [vo + vl - 1 for vo in voffs]

    nerr = verr = 0
    out = StringIO()
    for i in range(len(path)):
        if i == vs:
            out.write('@c')
            verr += 1
        elif i == ns:
            out.write('@r')
            nerr += 1
        elif subs:
            if i in voffs:
                out.write('@g')
            elif i in noffs:
                out.write('@m')

        out.write(path[i])

        if i == vs + vl - 1:
            out.write('@.')
            verr += 1
        elif i == ns + nl - 1:
            out.write('@.')
            nerr += 1
        elif subs:
            if i in vends or i in nends:
                out.write('@.')

    if errors:
        if nerr == 0:
            out.write(" @r{[no name]}")
        if verr == 0:
            out.write(" @r{[no version]}")
        if nerr == 1:
            out.write(" @r{[incomplete name]}")
        if verr == 1:
            out.write(" @r{[incomplete version]}")

    return colorize(out.getvalue())
Beispiel #14
0
def get_package_context(traceback, context=3):
    """Return some context for an error message when the build fails.

    Args:
        traceback (traceback): A traceback from some exception raised during
            install

        context (int): Lines of context to show before and after the line
            where the error happened

    This function inspects the stack to find where we failed in the
    package file, and it adds detailed context to the long_message
    from there.

    """
    def make_stack(tb, stack=None):
        """Tracebacks come out of the system in caller -> callee order.  Return
        an array in callee -> caller order so we can traverse it."""
        if stack is None:
            stack = []
        if tb is not None:
            make_stack(tb.tb_next, stack)
            stack.append(tb)
        return stack

    stack = make_stack(traceback)

    for tb in stack:
        frame = tb.tb_frame
        if 'self' in frame.f_locals:
            # Find the first proper subclass of PackageBase.
            obj = frame.f_locals['self']
            if isinstance(obj, spack.package.PackageBase):
                break

    # We found obj, the Package implementation we care about.
    # Point out the location in the install method where we failed.
    lines = [
        '{0}:{1:d}, in {2}:'.format(
            inspect.getfile(frame.f_code),
            frame.f_lineno - 1,  # subtract 1 because f_lineno is 0-indexed
            frame.f_code.co_name)
    ]

    # Build a message showing context in the install method.
    sourcelines, start = inspect.getsourcelines(frame)

    # Calculate lineno of the error relative to the start of the function.
    # Subtract 1 because f_lineno is 0-indexed.
    fun_lineno = frame.f_lineno - start - 1
    start_ctx = max(0, fun_lineno - context)
    sourcelines = sourcelines[start_ctx:fun_lineno + context + 1]

    for i, line in enumerate(sourcelines):
        is_error = start_ctx + i == fun_lineno
        mark = '>> ' if is_error else '   '
        # Add start to get lineno relative to start of file, not function.
        marked = '  {0}{1:-6d}{2}'.format(mark, start + start_ctx + i,
                                          line.rstrip())
        if is_error:
            marked = colorize('@R{%s}' % cescape(marked))
        lines.append(marked)

    return lines
Beispiel #15
0
def make_log_context(log_events, width=None):
    """Get error context from a log file.

    Args:
        log_events (list): list of events created by
            ``ctest_log_parser.parse()``
        width (int or None): wrap width; ``0`` for no limit; ``None`` to
            auto-size for terminal
    Returns:
        str: context from the build log with errors highlighted

    Parses the log file for lines containing errors, and prints them out
    with line numbers and context.  Errors are highlighted with '>>' and
    with red highlighting (if color is enabled).

    Events are sorted by line number before they are displayed.
    """
    error_lines = set(e.line_no for e in log_events)
    log_events = sorted(log_events, key=lambda e: e.line_no)

    num_width = len(str(max(error_lines or [0]))) + 4
    line_fmt = '%%-%dd%%s' % num_width
    indent = ' ' * (5 + num_width)

    if width is None:
        _, width = tty.terminal_size()
    if width <= 0:
        width = sys.maxsize
    wrap_width = width - num_width - 6

    out = StringIO()
    next_line = 1
    for event in log_events:
        start = event.start

        if isinstance(event, BuildError):
            color = 'R'
        elif isinstance(event, BuildWarning):
            color = 'Y'
        else:
            color = 'W'

        if next_line != 1 and start > next_line:
            out.write('\n     ...\n\n')

        if start < next_line:
            start = next_line

        for i in range(start, event.end):
            # wrap to width
            lines = _wrap(event[i], wrap_width)
            lines[1:] = [indent + ln for ln in lines[1:]]
            wrapped_line = line_fmt % (i, '\n'.join(lines))

            if i in error_lines:
                out.write(
                    colorize('  @%s{>> %s}\n' %
                             (color, cescape(wrapped_line))))
            else:
                out.write('     %s\n' % wrapped_line)

        next_line = event.end

    return out.getvalue()
Beispiel #16
0
def print_text_info(pkg):
    """Print out a plain text description of a package."""

    header = section_title(
        '{0}:   '
    ).format(pkg.build_system_class) + pkg.name
    color.cprint(header)

    color.cprint('')
    color.cprint(section_title('Description:'))
    if pkg.__doc__:
        color.cprint(color.cescape(pkg.format_doc(indent=4)))
    else:
        color.cprint("    None")

    color.cprint(section_title('Homepage: ') + pkg.homepage)

    if len(pkg.maintainers) > 0:
        mnt = " ".join(['@@' + m for m in pkg.maintainers])
        color.cprint('')
        color.cprint(section_title('Maintainers: ') + mnt)

    color.cprint('')
    color.cprint(section_title("Tags: "))
    if hasattr(pkg, 'tags'):
        tags = sorted(pkg.tags)
        colify(tags, indent=4)
    else:
        color.cprint("    None")

    color.cprint('')
    color.cprint(section_title('Preferred version:  '))

    if not pkg.versions:
        color.cprint(version('    None'))
        color.cprint('')
        color.cprint(section_title('Safe versions:  '))
        color.cprint(version('    None'))
    else:
        pad = padder(pkg.versions, 4)

        # Here we sort first on the fact that a version is marked
        # as preferred in the package, then on the fact that the
        # version is not develop, then lexicographically
        key_fn = lambda v: (pkg.versions[v].get('preferred', False),
                            not v.isdevelop(),
                            v)
        preferred = sorted(pkg.versions, key=key_fn).pop()

        f = fs.for_package_version(pkg, preferred)
        line = version('    {0}'.format(pad(preferred))) + color.cescape(f)
        color.cprint(line)
        color.cprint('')
        color.cprint(section_title('Safe versions:  '))

        for v in reversed(sorted(pkg.versions)):
            f = fs.for_package_version(pkg, v)
            line = version('    {0}'.format(pad(v))) + color.cescape(f)
            color.cprint(line)

    color.cprint('')
    color.cprint(section_title('Variants:'))

    formatter = VariantFormatter(pkg.variants)
    for line in formatter.lines:
        color.cprint(line)

    color.cprint('')
    color.cprint(section_title('Installation Phases:'))
    phase_str = ''
    for phase in pkg.phases:
        phase_str += "    {0}".format(phase)
    color.cprint(phase_str)

    for deptype in ('build', 'link', 'run'):
        color.cprint('')
        color.cprint(section_title('%s Dependencies:' % deptype.capitalize()))
        deps = sorted(pkg.dependencies_of_type(deptype))
        if deps:
            colify(deps, indent=4)
        else:
            color.cprint('    None')

    color.cprint('')
    color.cprint(section_title('Virtual Packages: '))
    if pkg.provided:
        inverse_map = {}
        for spec, whens in pkg.provided.items():
            for when in whens:
                if when not in inverse_map:
                    inverse_map[when] = set()
                inverse_map[when].add(spec)
        for when, specs in reversed(sorted(inverse_map.items())):
            line = "    %s provides %s" % (
                when.colorized(), ', '.join(s.colorized() for s in specs)
            )
            print(line)

    else:
        color.cprint("    None")

    color.cprint('')
Beispiel #17
0
def get_package_context(traceback, context=3):
    """Return some context for an error message when the build fails.

    Args:
        traceback (traceback): A traceback from some exception raised during
            install
        context (int): Lines of context to show before and after the line
            where the error happened

    This function inspects the stack to find where we failed in the
    package file, and it adds detailed context to the long_message
    from there.

    """
    def make_stack(tb, stack=None):
        """Tracebacks come out of the system in caller -> callee order.  Return
        an array in callee -> caller order so we can traverse it."""
        if stack is None:
            stack = []
        if tb is not None:
            make_stack(tb.tb_next, stack)
            stack.append(tb)
        return stack

    stack = make_stack(traceback)

    for tb in stack:
        frame = tb.tb_frame
        if 'self' in frame.f_locals:
            # Find the first proper subclass of PackageBase.
            obj = frame.f_locals['self']
            if isinstance(obj, spack.package.PackageBase):
                break

    # We found obj, the Package implementation we care about.
    # Point out the location in the install method where we failed.
    lines = [
        '{0}:{1:d}, in {2}:'.format(
            inspect.getfile(frame.f_code),
            frame.f_lineno - 1,  # subtract 1 because f_lineno is 0-indexed
            frame.f_code.co_name
        )
    ]

    # Build a message showing context in the install method.
    sourcelines, start = inspect.getsourcelines(frame)

    # Calculate lineno of the error relative to the start of the function.
    # Subtract 1 because f_lineno is 0-indexed.
    fun_lineno = frame.f_lineno - start - 1
    start_ctx = max(0, fun_lineno - context)
    sourcelines = sourcelines[start_ctx:fun_lineno + context + 1]

    for i, line in enumerate(sourcelines):
        is_error = start_ctx + i == fun_lineno
        mark = '>> ' if is_error else '   '
        # Add start to get lineno relative to start of file, not function.
        marked = '  {0}{1:-6d}{2}'.format(
            mark, start + start_ctx + i, line.rstrip())
        if is_error:
            marked = colorize('@R{%s}' % cescape(marked))
        lines.append(marked)

    return lines
Beispiel #18
0
def make_log_context(log_events, width=None):
    """Get error context from a log file.

    Args:
        log_events (list of LogEvent): list of events created by
            ``ctest_log_parser.parse()``
        width (int or None): wrap width; ``0`` for no limit; ``None`` to
            auto-size for terminal
    Returns:
        str: context from the build log with errors highlighted

    Parses the log file for lines containing errors, and prints them out
    with line numbers and context.  Errors are highlighted with '>>' and
    with red highlighting (if color is enabled).

    Events are sorted by line number before they are displayed.
    """
    error_lines = set(e.line_no for e in log_events)
    log_events = sorted(log_events, key=lambda e: e.line_no)

    num_width = len(str(max(error_lines))) + 4
    line_fmt = '%%-%dd%%s' % num_width
    indent = ' ' * (5 + num_width)

    if width is None:
        _, width = tty.terminal_size()
    if width <= 0:
        width = sys.maxsize
    wrap_width = width - num_width - 6

    out = StringIO()
    next_line = 1
    for event in log_events:
        start = event.start

        if isinstance(event, BuildError):
            color = 'R'
        elif isinstance(event, BuildWarning):
            color = 'Y'
        else:
            color = 'W'

        if next_line != 1 and start > next_line:
            out.write('\n     ...\n\n')

        if start < next_line:
            start = next_line

        for i in range(start, event.end):
            # wrap to width
            lines = _wrap(event[i], wrap_width)
            lines[1:] = [indent + l for l in lines[1:]]
            wrapped_line = line_fmt % (i, '\n'.join(lines))

            if i in error_lines:
                out.write(colorize(
                    '  @%s{>> %s}\n' % (color, cescape(wrapped_line))))
            else:
                out.write('     %s\n' % wrapped_line)

        next_line = event.end

    return out.getvalue()
Beispiel #19
0
def print_text_info(pkg):
    """Print out a plain text description of a package."""

    header = section_title('{0}:   ').format(pkg.build_system_class) + pkg.name
    color.cprint(header)

    color.cprint('')
    color.cprint(section_title('Description:'))
    if pkg.__doc__:
        color.cprint(color.cescape(pkg.format_doc(indent=4)))
    else:
        color.cprint("    None")

    color.cprint(section_title('Homepage: ') + pkg.homepage)

    if len(pkg.maintainers) > 0:
        mnt = " ".join(['@@' + m for m in pkg.maintainers])
        color.cprint('')
        color.cprint(section_title('Maintainers: ') + mnt)

    color.cprint('')
    color.cprint(section_title('Externally Detectable: '))

    # If the package has an 'executables' field, it can detect an installation
    if hasattr(pkg, 'executables'):
        find_attributes = []
        if hasattr(pkg, 'determine_version'):
            find_attributes.append('version')

        if hasattr(pkg, 'determine_variants'):
            find_attributes.append('variants')

        # If the package does not define 'determine_version' nor
        # 'determine_variants', then it must use some custom detection
        # mechanism. In this case, just inform the user it's detectable somehow.
        color.cprint('    True{0}'.format(' (' + ', '.join(find_attributes) +
                                          ')' if find_attributes else ''))
    else:
        color.cprint('    False')

    color.cprint('')
    color.cprint(section_title("Tags: "))
    if hasattr(pkg, 'tags'):
        tags = sorted(pkg.tags)
        colify(tags, indent=4)
    else:
        color.cprint("    None")

    color.cprint('')
    color.cprint(section_title('Preferred version:  '))

    if not pkg.versions:
        color.cprint(version('    None'))
        color.cprint('')
        color.cprint(section_title('Safe versions:  '))
        color.cprint(version('    None'))
        color.cprint('')
        color.cprint(section_title('Deprecated versions:  '))
        color.cprint(version('    None'))
    else:
        pad = padder(pkg.versions, 4)

        preferred = preferred_version(pkg)
        url = ''
        if pkg.has_code:
            url = fs.for_package_version(pkg, preferred)

        line = version('    {0}'.format(pad(preferred))) + color.cescape(url)
        color.cprint(line)

        safe = []
        deprecated = []
        for v in reversed(sorted(pkg.versions)):
            if pkg.has_code:
                url = fs.for_package_version(pkg, v)
            if pkg.versions[v].get('deprecated', False):
                deprecated.append((v, url))
            else:
                safe.append((v, url))

        for title, vers in [('Safe', safe), ('Deprecated', deprecated)]:
            color.cprint('')
            color.cprint(section_title('{0} versions:  '.format(title)))
            if not vers:
                color.cprint(version('    None'))
                continue

            for v, url in vers:
                line = version('    {0}'.format(pad(v))) + color.cescape(url)
                color.cprint(line)

    color.cprint('')
    color.cprint(section_title('Variants:'))

    formatter = VariantFormatter(pkg.variants)
    for line in formatter.lines:
        color.cprint(color.cescape(line))

    if hasattr(pkg, 'phases') and pkg.phases:
        color.cprint('')
        color.cprint(section_title('Installation Phases:'))
        phase_str = ''
        for phase in pkg.phases:
            phase_str += "    {0}".format(phase)
        color.cprint(phase_str)

    for deptype in ('build', 'link', 'run'):
        color.cprint('')
        color.cprint(section_title('%s Dependencies:' % deptype.capitalize()))
        deps = sorted(pkg.dependencies_of_type(deptype))
        if deps:
            colify(deps, indent=4)
        else:
            color.cprint('    None')

    color.cprint('')
    color.cprint(section_title('Virtual Packages: '))
    if pkg.provided:
        inverse_map = {}
        for spec, whens in pkg.provided.items():
            for when in whens:
                if when not in inverse_map:
                    inverse_map[when] = set()
                inverse_map[when].add(spec)
        for when, specs in reversed(sorted(inverse_map.items())):
            line = "    %s provides %s" % (when.colorized(), ', '.join(
                s.colorized() for s in specs))
            print(line)

    else:
        color.cprint("    None")

    color.cprint('')