#!/usr/bin/env python
#******************************************************************************\
#* Copyright (C) 2003-2004 Martin Blais <blais@furius.ca>
#*
#* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#*
#*****************************************************************************/

"""match-files [<options>] [<file> ... (many files...) ]

Match files from different directories in pairs according to their basename and
output the results where a match has succeeded, printing two filenames per-line
of output.

This can be used to implement processing in two similar directories, for
example, combining it with xargs::

  match-files -x '--single' dir1/*.c dir2/*.c | xargs -n2 xxdiff

will result in::

  xxdiff dir1/file1.c dir2/file1.c
  xxdiff dir1/file2.c dir2/file2.c
  xxdiff dir1/file3.c dir2/file3.c
  ...

The way we implement the heuristic to match up files is simple: we match up the
basenames of the files.  The files are always printed in the order that they
show up on the command-line.

Also, you can match the file extensions instead of the basename as the matching
string to implement a sort of 'zip' of the filenames, e.g.::

  match-files -e file1.{h,cpp} file2.{h,cpp} | xargs -n2 mv 

will result in::

  mv file1.cpp file2.cpp
  mv file1.h   file2.h

By default, a matching filename is printed out only when there are exactly 2
files matching the matching part.  This number can be changed with an option.
"""

__version__ = "Revision: 1.4 "
__author__ = "Martin Blais <blais@furius.ca>"


import sys, os


def main():
    import optparse
    parser = optparse.OptionParser(__doc__.strip(), version=__version__)
    parser.add_option('-x', '--extra', action='store',
                      help="prepend the given string for single files "
                      "instead of ignoring them")
    parser.add_option('-n', '--number', action='store', type='int',
                      default=2,
                      help="print only matches with the given number of files")
    parser.add_option('-e', '--extension', action='store_true',
                      help="Use extension as matching prefix instead of the "
                      "basename.")
    opts, files = parser.parse_args()
    
    try:
        # build map of basenames
        bnmap = {}
        for fn in files:
            dn, bn = os.path.split(fn)
            if opts.extension:
                b, bn = os.path.splitext(bn)
            bnmap.setdefault(bn, []).append(fn)
        
        # invoke xxdiff's on alphabetical order of the basenames
        bnkeys = bnmap.keys()
        bnkeys.sort()
        for bn in bnkeys:
            l = bnmap[bn]
            if len(l) == opts.number:
                print ' '.join(l)

            elif len(l) == 1 and opts.extra:
                print opts.extra + ' ' + ' '.join(l)
            else:
                # ignore the files.
                continue

    except KeyboardInterrupt, e:
        print >> sys.stderr, 'Interrupted.'
        sys.exit(1)

if __name__ == '__main__':
    main()
