#!/usr/bin/env python3
"""
Generate lists of files based on extensions repeated occurences of parts of
filenames.

This is useful for quickly grep-finding through a large number of files. Like
this, for example, from within Emacs::

  cat ~/project/build./files/files.h  | xargs grep -nE Kwds
  
"""
__author__ = 'Martin Blais <blais@furius.ca>'

import os, re
from os.path import *
from collections import defaultdict


def split_extension(fn):
    return splitext(fn)
    ## comps = fn.split('.', 1)
    ## return (comps + ['']) if len(comps) == 1 else comps

def writelist(outdir, id, flist):
    out = join(outdir, ('files%s' % id) if id.startswith('.') else ('files.%s' % id))
    with open(out, 'w') as f:
        for fn in flist:
            f.write('%s\n' % fn)
    return out

def main():
    import optparse
    parser = optparse.OptionParser(__doc__.strip())

    parser.add_option('-o', '--output', action='store',
                      default=os.getcwd(),
                      help="Output directory (default: CWD).")

    parser.add_option('-I', '--ignores', action='append',
                      default=[r'\.hg', r'\.svn', r'\.git',
                               'core', r'.*\.o$', r'.*\.pyc$', r'.*\.bak$'],
                      help="Patterns of files or directories to ignore.")

    opts, args = parser.parse_args()
    if len(args) == 0:
        root_ = os.getcwd()
    elif len(args) == 1:
        root_ = args[0]
    else:
        parser.error("Usage: [ROOT]")
    root_ = abspath(root_)

    if not exists(opts.output):
        os.makedirs(opts.output)

    pfxmap, sfxmap = defaultdict(list), defaultdict(list)
    for root, dirs, files in os.walk(root_):
        dirs[:] = [n
                   for n in dirs
                   if not any(re.match(x, n) for x in opts.ignores) and ' ' not in n]
        files[:] = [n
                    for n in files
                    if not any(re.match(x, n) for x in opts.ignores) and ' ' not in n]

        for fn in files:
            pfx, sfx = split_extension(fn)
            pfxmap[pfx].append(join(root, fn))
            sfxmap[sfx].append(join(root, fn))

    for pfx, flist in sorted(pfxmap.items()):
        if len(flist) > 3:
            print(writelist(opts.output, pfx, flist))

    for sfx, flist in sorted(sfxmap.items()):
        if not sfx:
            continue
        print(writelist(opts.output, sfx, flist))


if __name__ == '__main__':
    main()
