#!/Users/luckow/workspace-saga/bigjob/BigJob/bootstrap/.bigjob/python/bin/python
# -*- coding: utf-8 -*-
#
# Grep-like utility understanding hostlists

__version__ = "1.14"

# Copyright (C) 2009 Kent Engström <kent@nsc.liu.se>
# 
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.

import sys
import optparse
import re

from hostlist import expand_hostlist, collect_hostlist, numerically_sorted, BadHostlist, __version__ as library_version

def die(s, exit_code = 1):
    sys.stderr.write(s + "\n")
    sys.exit(1)

finder = re.compile(r'[A-Za-z0-9]+(\[[0-9,-]+\])*')
def hosts_from_line(line):
    words = set()
    for m in finder.finditer(line):
        word = m.group(0)
        if not '[' in word:
            words.add(word)
        else:
            try:
                hosts = expand_hostlist(word)
                for host in hosts:
                    words.add(host)
            except BadHostlist:
                words.add(word)
    return words

def emit(line, filename, line_no):
    if opts.line_number:
        line = str(line_no) + ":" + line
    if do_print_filename:
        line = filename + ":" + line
    sys.stdout.write(line)

def search(f, filename):
    line_no = 0
    for line in f:
        line_no += 1
        words = hosts_from_line(line)
        if opts.all:
            does_match = search_set <= words
        else:
            does_match = search_set & words
        if bool(does_match) ^ bool(opts.invert_match):
            emit(line, filename, line_no)


# MAIN

op = optparse.OptionParser(usage="usage: %prog [OPTION]... HOSTLIST [FILES]...",
                           add_help_option = False)
op.add_option("--all",
              action="store_true",
              help="Require all hosts in the hostlist to be found in the line.")
op.add_option("--any",
              action="store_false", dest = "all",
              help="Require some host in the hostlist to be found in the line (default).")
op.add_option("-h", "--no-filename",
              action="store_false", dest = "print_filename",
              help="Do not show filename before match (default for <= 1 file)")
op.add_option("-H", "--with-filename",
              action="store_true", dest = "print_filename",
              help="Show filename before match (default for > 1 file)")
op.add_option("-v", "--invert-match",
              action="store_true",
              help="Invert the sense of matching, to select non-matching lines.")
op.add_option("-n", "--line-number",
              action="store_true",
              help="Show line number before match")
op.add_option("--help", action="help", help="Show help")
op.add_option("--version",
              action="store_true",
              help="Show version")
(opts, args) = op.parse_args()

if opts.version:
    print "Version %s (library version %s)" % (__version__,
                                               library_version)
    sys.exit()

if len(args) < 1:
    die("You must specify a hostlist")
else:
    search_list = args[0]

search_set = set(expand_hostlist(search_list))

if opts.print_filename in (True, False):
    do_print_filename = opts.print_filename
else:
    if len(args) > 2:
        do_print_filename = True
    else:
        do_print_filename = False

try:
    if len(args) == 1:
        # Seach stdin
        search(sys.stdin, "(standard input)")
    else:
        for filename in args[1:]:
            f = open(filename)
            search(f, filename)
            f.close()
except KeyboardInterrupt:
    sys.exit()
except IOError, e:
    sys.stderr.write(e.strerror + " '" + e.filename + "'\n")
    sys.exit(1)
