#!/usr/bin/env python3

"""
See the help message (--help).
"""

from argparse import ArgumentParser
from fnmatch import fnmatch
from os import walk
from os.path import abspath, realpath, join
from pycman import config
from sys import stderr



parser = ArgumentParser(description='List unpackaged files in given directories.')
parser.add_argument(
  'dirs', metavar='<dirpath>', nargs='+', help='directories to search'
)
parser.add_argument(
  '-e', '--empty', action='store_true', help='list empty directories'
)
parser.add_argument(
  '-i', '--ignore', metavar='<glob pattern>', action='append', default=[],
  help='glob patterns to ignore'
)
parser.add_argument(
  '-c', '--config', metavar='<path>', default='/etc/pacman.conf',
  help='Pacman configuration file'
)


def main(args=None):
  args = parser.parse_args(args)
  h = config.init_with_config(args.config)
  db = h.get_localdb()

  owned = set()
  last_w = 0
  for pkg in db.pkgcache:
    msg = '\radding files from %s to list' % pkg.name
    w = len(msg)
    msg += (last_w - w) * ' '
    last_w = w
    stderr.write(msg)
    for f in pkg.files:
      install_path = '/' + f[0]
      owned.add(install_path)
      # Avoid false positives due to symbolic links.
      real_path = realpath(install_path)
      owned.add(real_path)

  stderr.write('\r' + ' ' * last_w + '\r')

  def ignore(path):
    if args.ignore:
      for p in args.ignore:
        if fnmatch(path, p):
          return True
    return False


  for d in args.dirs:
    d = abspath(d)
    for root, dirs, files in walk(d, topdown=True, followlinks=False):
      if ignore(root):
        dirs[:] = []
        files[:] = []
        continue
      if not dirs and not files:
        if args.empty:
          print(root)
        continue
      for f in files:
        fpath = join(root, f)
        if not ignore(fpath) and fpath not in owned:
          print(fpath)

if __name__ == '__main__':
  try:
    main()
  except (KeyboardInterrupt, BrokenPipeError):
    pass
