Clean up find command, move code to utils.

This commit is contained in:
Todd Gamblin 2014-04-14 12:53:23 -07:00
parent 1e51daab08
commit 1f9dfeb9b5
5 changed files with 99 additions and 58 deletions

View File

@ -31,6 +31,22 @@
# Ignore emacs backups when listing modules # Ignore emacs backups when listing modules
ignore_modules = [r'^\.#', '~$'] ignore_modules = [r'^\.#', '~$']
def partition_list(elements, predicate):
"""Partition a list into two lists, the first containing elements
for which the predicate evaluates to true, the second containing
those for which it is false.
"""
trues = []
falses = []
for elt in elements:
if predicate(elt):
trues.append(elt)
else:
falses.append(elt)
return trues, falses
def caller_locals(): def caller_locals():
"""This will return the locals of the *parent* of the caller. """This will return the locals of the *parent* of the caller.
This allows a fucntion to insert variables into its caller's This allows a fucntion to insert variables into its caller's

View File

@ -23,7 +23,10 @@
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
############################################################################## ##############################################################################
import sys import sys
import os
import textwrap import textwrap
from StringIO import StringIO
from llnl.util.tty.color import * from llnl.util.tty.color import *
debug = False debug = False
@ -97,3 +100,61 @@ def get_number(prompt, **kwargs):
elif default is not None: elif default is not None:
number = default number = default
return number return number
def hline(label=None, **kwargs):
"""Draw an optionally colored or labeled horizontal line.
Options:
char Char to draw the line with. Default '-'
color Color of the label. Default is no color.
max_width Maximum width of the line. Default is 64 chars.
See tty.color for possible color formats.
"""
char = kwargs.get('char', '-')
color = kwargs.get('color', '')
max_width = kwargs.get('max_width', 64)
cols, rows = terminal_size()
if not cols:
cols = max_width
else:
cols -= 2
cols = min(max_width, cols)
label = str(label)
prefix = char * 2 + " " + label + " "
suffix = (cols - len(prefix)) * char
out = StringIO()
if color:
prefix = char * 2 + " " + color + cescape(label) + "@. "
cwrite(prefix, stream=out, color=True)
else:
out.write(prefix)
out.write(suffix)
print out.getvalue()
def terminal_size():
"""Gets the dimensions of the console: cols, rows."""
def ioctl_GWINSZ(fd):
try:
cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234'))
except:
return
return cr
cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
if not cr:
try:
fd = os.open(os.ctermid(), os.O_RDONLY)
cr = ioctl_GWINSZ(fd)
os.close(fd)
except:
pass
if not cr:
cr = (os.environ.get('LINES', 25), os.environ.get('COLUMNS', 80))
return int(cr[1]), int(cr[0])

View File

@ -38,27 +38,7 @@
import termios import termios
import struct import struct
def get_terminal_size(): from llnl.util.tty import terminal_size
"""Get the dimensions of the console."""
def ioctl_GWINSZ(fd):
try:
cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234'))
except:
return
return cr
cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
if not cr:
try:
fd = os.open(os.ctermid(), os.O_RDONLY)
cr = ioctl_GWINSZ(fd)
os.close(fd)
except:
pass
if not cr:
cr = (os.environ.get('LINES', 25), os.environ.get('COLUMNS', 80))
return int(cr[1]), int(cr[0])
class ColumnConfig: class ColumnConfig:
def __init__(self, cols): def __init__(self, cols):
@ -135,7 +115,7 @@ def colify(elts, **options):
console_cols = options.get("cols", None) console_cols = options.get("cols", None)
if not console_cols: if not console_cols:
console_cols, console_rows = get_terminal_size() console_cols, console_rows = terminal_size()
elif type(console_cols) != int: elif type(console_cols) != int:
raise ValueError("Number of columns must be an int") raise ValueError("Number of columns must be an int")
console_cols = max(1, console_cols - indent) console_cols = max(1, console_cols - indent)
@ -170,7 +150,7 @@ def colify(elts, **options):
if __name__ == "__main__": if __name__ == "__main__":
import optparse import optparse
cols, rows = get_terminal_size() cols, rows = terminal_size()
parser = optparse.OptionParser() parser = optparse.OptionParser()
parser.add_option("-u", "--uniform", action="store_true", default=False, parser.add_option("-u", "--uniform", action="store_true", default=False,
help="Use uniformly sized columns instead of variable-size.") help="Use uniformly sized columns instead of variable-size.")

View File

@ -26,13 +26,13 @@
import argparse import argparse
from StringIO import StringIO from StringIO import StringIO
from llnl.util.tty.colify import colify, get_terminal_size import llnl.util.tty as tty
from llnl.util.tty.colify import colify
from llnl.util.tty.color import * from llnl.util.tty.color import *
from llnl.util.lang import partition_list
import spack import spack
import spack.spec import spack.spec
import spack
description ="Find installed spack packages" description ="Find installed spack packages"
@ -48,42 +48,25 @@ def setup_parser(subparser):
help='optional specs to filter results') help='optional specs to filter results')
# TODO: move this and colify to tty.
def hline(label, char, color=''):
max_width = 64
cols, rows = get_terminal_size()
if not cols:
cols = max_width
else:
cols -= 2
cols = min(max_width, cols)
label = str(label)
prefix = char * 2 + " " + label + " "
suffix = (cols - len(prefix)) * char
out = StringIO()
if color:
prefix = char * 2 + " " + color + cescape(label) + "@. "
cwrite(prefix, stream=out, color=True)
else:
out.write(prefix)
out.write(suffix)
return out.getvalue()
def find(parser, args): def find(parser, args):
def hasher(): def hasher():
return collections.defaultdict(hasher) return collections.defaultdict(hasher)
query_specs = [] # Filter out specs that don't exist.
if args.query_specs: query_specs = spack.cmd.parse_specs(args.query_specs)
query_specs = spack.cmd.parse_specs(args.query_specs, normalize=True) query_specs, nonexisting = partition_list(
query_specs, lambda s: spack.db.exists(s.name))
if nonexisting:
msg = "No such package%s: " % ('s' if len(nonexisting) > 1 else '')
tty.msg(msg + ", ".join(s.name for s in nonexisting))
if not query_specs:
return
# Make a dict with specs keyed by architecture and compiler. # Make a dict with specs keyed by architecture and compiler.
index = hasher() index = hasher()
for spec in spack.db.installed_package_specs(): for spec in spack.db.installed_package_specs():
# Check whether this installed package matches any query.
if query_specs and not any(spec.satisfies(q) for q in query_specs): if query_specs and not any(spec.satisfies(q) for q in query_specs):
continue continue
@ -93,9 +76,9 @@ def hasher():
# Traverse the index and print out each package # Traverse the index and print out each package
for architecture in index: for architecture in index:
print hline(architecture, "=", spack.spec.architecture_color) tty.hline(architecture, char='=', color=spack.spec.architecture_color)
for compiler in index[architecture]: for compiler in index[architecture]:
print hline(compiler, "-", spack.spec.compiler_color) tty.hline(architecture, char='-', color=spack.spec.compiler_color)
specs = index[architecture][compiler] specs = index[architecture][compiler]
specs.sort() specs.sort()

View File

@ -326,7 +326,9 @@ class SomePackage(Package):
"""Controls whether install and uninstall check deps before running.""" """Controls whether install and uninstall check deps before running."""
ignore_dependencies = False ignore_dependencies = False
"""Dirty hack for forcing packages with uninterpretable URLs""" """Dirty hack for forcing packages with uninterpretable URLs
TODO: get rid of this.
"""
force_url = False force_url = False
@ -676,7 +678,6 @@ def do_install(self):
if os.path.exists(self.prefix): if os.path.exists(self.prefix):
tty.msg("%s is already installed." % self.name) tty.msg("%s is already installed." % self.name)
print_pkg(self.prefix)
return return
if not self.ignore_dependencies: if not self.ignore_dependencies: