#!/usr/bin/env python2.7
# pylint:disable=missing-docstring,invalid-name,redefined-outer-name,too-few-public-methods
"""\
usage: pgctl-fuser file [file ...]

Shows the pids (of the current user) that have this file opened.
This is useful for finding which processes hold a file lock (flock).
This has the same behavior as `lsof -t file`, but is *much* faster.
"""
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals

from .debug import trace


def stat(path):
    from os import stat
    try:
        path = stat(path)
    except EnvironmentError as error:
        trace('fuser suppressed: %s', error)
        return None
    else:
        return (path.st_ino, path.st_dev)


def listdir(path):
    from os import listdir
    try:
        return listdir(path)
    except EnvironmentError as error:
        trace('fuser suppressed: %s', error)
        return ()


def fuser(path):
    """Return the list of pids that have 'path' open, for the current user"""
    search = stat(path)
    if search is None:
        return

    from glob import glob
    for fddir in glob('/proc/*/fd/'):
        try:
            pid = int(fddir.split('/', 3)[2])
        except ValueError:
            continue

        fds = listdir(fddir)
        for fd in fds:
            from os.path import join
            fd = join(fddir, fd)
            found = stat(fd)
            if found == search:
                yield pid
                break


def main():
    from sys import argv
    try:
        path = argv[1]
    except IndexError:
        return __doc__

    for pid in fuser(path):
        print(pid)


if __name__ == '__main__':
    exit(main())

@@ -133,16 +133,21 @@
 tl-fuser
+ %5B-d%5D
  file %5Bf
@@ -489,27 +489,135 @@
 rom 
-.debug import trace
+collections import namedtuple%0A%0Afrom .debug import trace%0A%0AStatTuple = namedtuple('StatTuple', ('st_ino', 'std_dev', 'st_nlink'))
 %0A%0A%0Ad
@@ -818,16 +818,25 @@
  return 
+StatTuple
 (path.st
@@ -852,16 +852,31 @@
 h.st_dev
+, path.st_nlink
 )%0A%0A%0Adef 
@@ -1068,24 +1068,45 @@
 f fuser(path
+, allow_deleted=False
 ):%0A    %22%22%22Re
@@ -1219,16 +1219,38 @@
  is None
+ and not allow_deleted
 :%0A      
@@ -1663,16 +1663,223 @@
  break%0A%0A
+            if allow_deleted and found.st_nlink == 0:%0A                from os import readlink%0A                if readlink(fd) == path + ' (deleted)':%0A                    yield pid%0A                    break%0A%0A
 %0Adef mai
@@ -1880,16 +1880,25 @@
 ef main(
+args=None
 ):%0A    f
@@ -1905,131 +1905,460 @@
 rom 
-sys import argv%0A    try:%0A        path = argv%5B1%5D%0A    except IndexError:%0A        return __doc__%0A%0A    for pid in fuser(path):%0A
+argparse import ArgumentParser%0A    from sys import argv%0A    args = args or argv%0A%0A    parser = ArgumentParser(description=__doc__)%0A    parser.add_argument('-d', '--allow-deleted', action='store_true', help='allow deleted files')%0A    parser.add_argument('file', nargs='+')%0A    args = parser.parse_args(args%5B1:%5D)%0A    if not args.file:%0A        parser.print_help()%0A%0A    for f in args.file:%0A        for pid in fuser(f, allow_deleted=args.allow_deleted):%0A    
     

add allow-deleted option to fuser