#!/usr/bin/env python

"""\
py.cleanup [PATH] ...

Delete typical python development related files recursively under the specified PATH (which defaults to the current working directory). Don't follow links and don't recurse into directories with a dot.  Optionally remove setup.py related files and empty
directories.

"""
import py
import sys, subprocess

def main():
    parser = py.std.optparse.OptionParser(usage=__doc__)
    parser.add_option("-e", metavar="ENDING",
        dest="endings", default=[".pyc", "$py.class"], action="append",
        help=("(multi) recursively remove files with the given ending."
             " '.pyc' and '$py.class' are in the default list."))
    parser.add_option("-d", action="store_true", dest="removedir",
                      help="remove empty directories.")
    parser.add_option("-p", action="store_true", dest="pycache",
                      help="remove __pycache__ directories.")
    parser.add_option("-s", action="store_true", dest="setup",
                      help="remove 'build' and 'dist' directories next to setup.py files")
    parser.add_option("-a", action="store_true", dest="all",
                      help="synonym for '-p -S -d -e pip-log.txt'")
    parser.add_option("-q", "--quiet", action="store_true", dest="quiet",
                      help="don't print each removed filename on output")
    parser.add_option("-n", "--dryrun", dest="dryrun", default=False,
        action="store_true",
        help="don't actually delete but display would-be-removed filenames.")
    (options, args) = parser.parse_args()

    Cleanup(options, args).main()

class Cleanup:
    def __init__(self, options, args):
        if not args:
            args = ["."]
        self.options = options
        self.args = [py.path.local(x) for x in args]
        if options.all:
            options.setup = True
            options.removedir = True
            options.pycache = True
            options.endings.append("pip-log.txt")

    def main(self):
        if self.options.setup:
            for arg in self.args:
                self.setupclean(arg)

        for path in self.args:
            py.builtin.print_("cleaning path", path,
                "of extensions", self.options.endings)
            for x in path.visit(self.shouldremove, self.recursedir):
                self.remove(x)
        if self.options.removedir:
            for x in path.visit(lambda x: x.check(dir=1), self.recursedir):
                if not x.listdir():
                    self.remove(x)

    def shouldremove(self, p):
        if p.check(file=1):
            for ending in self.options.endings:
                if p.basename.endswith(ending):
                    return True
            return False
        if self.options.pycache and p.basename == "__pycache__":
            return True

    def recursedir(self, path):
        return path.check(dotfile=0, link=0)

    def remove(self, path):
        if not path.check():
            return
        if self.options.dryrun:
            py.builtin.print_("would remove", path)
        else:
            if not self.options.quiet:
                py.builtin.print_("removing", path)
            path.remove()

    def XXXcallsetup(self, setup, *args):
        old = setup.dirpath().chdir()
        try:
            subprocess.call([sys.executable, str(setup)] + list(args))
        finally:
            old.chdir()

    def setupclean(self, path):
        for x in path.visit("setup.py", self.recursedir):
            basepath = x.dirpath()
            self.remove(basepath / "build")
            self.remove(basepath / "dist")
