py2app picking up .git subdir of a package during build
Question: We use py2app extensively at our facility to produce self contained .app
packages for easy internal deployment without dependency issues. Something I
noticed recently, and have no idea how it began, is that when building an
.app, py2app started including the .git directory of our main library.

commonLib, for instance, is our root python library package, which is a git
repo. Under this package are the various subpackages such as database,
utility, etc.

    
    
    commonLib/
        |- .git/ # because commonLib is a git repo
        |- __init__.py
        |- database/
            |- __init__.py
        |- utility/
            |- __init__.py
        # ... etc
    

In a given project, say Foo, we will do imports like `from commonLib import
xyz` to use our common packages. Building via py2app looks something like:
`python setup.py py2app`

So the recent issue I am seeing is that when building an app for project Foo,
I will see it include everything in commonLib/.git/ into the app, which is
extra bloat. py2app has an excludes option but that only seems to be for
python modules. I cant quite figure out what it would take to exclude the .git
subdir, or in fact, what is causing it to be included in the first place.

Has anyone experienced this when using a python package import that is a git
repo? Nothing has changed in our setup.py files for each project, and
commonLib has always been a git repo. So the only thing I can think of being a
variable is the version of py2app and its deps which have obviously been
upgraded over time.

_Edit_

I'm using the latest py2app 0.6.4 as of right now. Also, my setup.py was first
generated from py2applet a while back, but has been hand configured since and
copied over as a template for every new project. I am using PyQt4/sip for
every single one of these projects, so it also makes me wonder if its an issue
with one of the recipes?

### Update

From the first answer, I tried to fix this using various combinations of
`exclude_package_data` settings. Nothing seems to force the .git directory to
become excluded. Here is a sample of what my setup.py files generally look
like:

    
    
    from setuptools import setup
    from myApp import VERSION
    
    appname = 'MyApp'
    APP = ['myApp.py']
    DATA_FILES = []
    OPTIONS = {
        'includes': 'atexit, sip, PyQt4.QtCore, PyQt4.QtGui',
        'strip': True, 
        'iconfile':'ui/myApp.icns', 
        'resources':['src/myApp.png'], 
        'plist':{
            'CFBundleIconFile':'ui/myApp.icns',
            'CFBundleIdentifier':'com.company.myApp',
            'CFBundleGetInfoString': appname,
            'CFBundleVersion' : VERSION,
            'CFBundleShortVersionString' : VERSION
            }
        }
    
    setup(
        app=APP,
        data_files=DATA_FILES,
        options={'py2app': OPTIONS},
        setup_requires=['py2app'],
    )
    

I have tried things like:

    
    
    setup(
        ...
        exclude_package_data = { 'commonLib': ['.git'] },
        #exclude_package_data = { '': ['.git'] },
        #exclude_package_data = { 'commonLib/.git/': ['*'] },
        #exclude_package_data = { '.git': ['*'] },
        ...
    )
    

### Update #2

I have posted my own answer which does a monkeypatch on distutils. Its ugly
and not preferred, but until someone can offer me a better solution, I guess
this is what I have.


Answer: I am adding an answer to my own question, to document the only thing I have
found to work thus far. My approach was to monkeypatch distutils to ignore
certain patterns when creating a directory or copying a file. This is really
not what I wanted to do, but like I said, its the only thing that works so
far.

    
    
    ## setup.py ##
    
    import re
    
    # file_util has to come first because dir_util uses it
    from distutils import file_util, dir_util
    
    def wrapper(fn):
        def wrapped(src, *args, **kwargs):
            if not re.search(r'/\.git/?', src):
                fn(src, *args, **kwargs) 
        return wrapped       
    
    file_util.copy_file = wrapper(file_util.copy_file)
    dir_util.mkpath = wrapper(dir_util.mkpath)
    
    # now import setuptools so it uses the monkeypatched methods
    from setuptools import setup
    

Hopefully someone will comment on this and tell me a higher level approach to
avoid doing this. But as of now, I will probably wrap this into a utility
method like `exclude_data_patterns(re_pattern)` to be reused in my projects.

