Repository: conda/conda-build

Issue:
Bug from PR#866
attn @msarahan @brentp 
#866 causes an exception to be raised when any of the files are empty.  Since it is reasonably common to just have empty `__init__.py` files floating around in a python package, such an exception is pretty bad.  I just so happen to have some empty `__init__.py` files floating around in my software stack, so this broke my automated builds :cry: .  I unfortunately have zero experience with mmap and so am really unsure what the proper fix would be here.  I'm hoping that there is an easy way we can get a check around the offending line: https://github.com/conda/conda-build/pull/866/files#diff-ac55d744935b1f37a3369258b88e8f1fR111

Thoughts?

Here is a minimal python package that demonstrates this problem.

```
git clone https://github.com/ericdill/conda-build-866
cd conda-build-866
conda build conda-recipe
```

Should produce 

```
$ conda build conda-recipe/
Removing old build environment
Removing old work directory
BUILD START: conda-build-866-1-py35_0
Using Anaconda Cloud api site https://api.anaconda.org
Fetching package metadata: ..........
WARNING: Could not detect installed version of conda-build
Solving package specifications: .........

The following NEW packages will be INSTALLED:

    ncurses:    5.9-8         lightsource2
    openssl:    1.0.2g-0      defaults    
    pip:        8.1.1-py35_1  defaults    
    python:     3.5.1-0       defaults    
    readline:   6.2.5-1       lightsource2
    setuptools: 20.6.7-py35_0 defaults    
    sqlite:     3.9.2-0       defaults    
    tk:         8.5.18-0      defaults    
    wheel:      0.29.0-py35_0 defaults    
    xz:         5.0.5-1       defaults    
    zlib:       1.2.8-0       defaults    

Linking packages ...
[      COMPLETE      ]|##################################################################| 100%
Removing old work directory
From /home/edill/dev/conda/conda-build-866/conda-recipe/..
 * [new ref]                    -> _conda_cache_origin_head
checkout: '9f0b9c0d421cc3fe0de75714c5d3f3fdeae736ca'
Cloning into '/home/edill/miniconda/conda-bld/work'...
done.
Note: checking out '9f0b9c0d421cc3fe0de75714c5d3f3fdeae736ca'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

HEAD is now at 9f0b9c0... Initial commit
==> git log -n1 <==

commit 9f0b9c0d421cc3fe0de75714c5d3f3fdeae736ca
Author: Eric Dill <edill@bnl.gov>
Date:   Wed Apr 6 20:48:23 2016 -0400

    Initial commit


==> git describe --tags --dirty <==



==> git status <==

HEAD detached at 9f0b9c0
nothing to commit, working directory clean


Package: conda-build-866-1-py35_0
source tree in: /home/edill/miniconda/conda-bld/work
+ /home/edill/miniconda/envs/_build/bin/python setup.py install --single-version-externally-managed --record=/dev/null
running install
running build
running build_py
creating build
creating build/lib
creating build/lib/conda_build_866
copying conda_build_866/__init__.py -> build/lib/conda_build_866
running install_lib
creating /home/edill/miniconda/envs/_build/lib/python3.5/site-packages/conda_build_866
copying build/lib/conda_build_866/__init__.py -> /home/edill/miniconda/envs/_build/lib/python3.5/site-packages/conda_build_866
byte-compiling /home/edill/miniconda/envs/_build/lib/python3.5/site-packages/conda_build_866/__init__.py to __init__.cpython-35.pyc
running install_egg_info
running egg_info
creating bluesky.egg-info
writing dependency_links to bluesky.egg-info/dependency_links.txt
writing bluesky.egg-info/PKG-INFO
writing top-level names to bluesky.egg-info/top_level.txt
writing manifest file 'bluesky.egg-info/SOURCES.txt'
reading manifest file 'bluesky.egg-info/SOURCES.txt'
writing manifest file 'bluesky.egg-info/SOURCES.txt'
Copying bluesky.egg-info to /home/edill/miniconda/envs/_build/lib/python3.5/site-packages/bluesky-0.0.0-py3.5.egg-info
running install_scripts
writing list of installed files to '/dev/null'
number of files: 6
Fixing permissions
An unexpected error has occurred, please consider sending the
following traceback to the conda GitHub issue tracker at:

    https://github.com/conda/conda-build/issues

Include the output of the command 'conda info' in your report.


Traceback (most recent call last):
  File "/home/edill/miniconda/bin/conda-build", line 6, in <module>
    exec(compile(open(__file__).read(), __file__, 'exec'))
  File "/home/edill/dev/conda/conda-build/bin/conda-build", line 5, in <module>
    sys.exit(main())
  File "/home/edill/dev/conda/conda-build/conda_build/main_build.py", line 208, in main
    args_func(args, p)
  File "/home/edill/dev/conda/conda-build/conda_build/main_build.py", line 493, in args_func
    args.func(args, p)
  File "/home/edill/dev/conda/conda-build/conda_build/main_build.py", line 438, in execute
    include_recipe=args.include_recipe)
  File "/home/edill/dev/conda/conda-build/conda_build/build.py", line 513, in build
    include_recipe=bool(m.path) and include_recipe)
  File "/home/edill/dev/conda/conda-build/conda_build/build.py", line 235, in create_info_files
    files_with_prefix = sorted(have_prefix_files(files))
  File "/home/edill/dev/conda/conda-build/conda_build/build.py", line 111, in have_prefix_files
    mm = mmap.mmap(fi.fileno(), 0)
ValueError: cannot mmap an empty file
```

And the requisite `conda info`

```
$ conda info
Using Anaconda Cloud api site https://api.anaconda.org
Current conda install:

             platform : linux-64
        conda version : 4.0.5
  conda-build version : 1.20.0+50.g405c5ec
       python version : 3.5.1.final.0
     requests version : 2.9.1
     root environment : /home/edill/miniconda  (writable)
  default environment : /home/edill/miniconda
     envs directories : /home/edill/miniconda/envs
        package cache : /home/edill/miniconda/pkgs
         channel URLs : https://conda.anaconda.org/t/<TOKEN>/lightsource2-dev/linux-64/
                        https://conda.anaconda.org/t/<TOKEN>/lightsource2-dev/noarch/
                        https://conda.anaconda.org/t/<TOKEN>/lightsource2/linux-64/
                        https://conda.anaconda.org/t/<TOKEN>/lightsource2/noarch/
                        https://repo.continuum.io/pkgs/free/linux-64/
                        https://repo.continuum.io/pkgs/free/noarch/
                        https://repo.continuum.io/pkgs/pro/linux-64/
                        https://repo.continuum.io/pkgs/pro/noarch/
          config file : /home/edill/.condarc
    is foreign system : False
```

and `conda list -e`

```
$ conda list -e
# This file may be used to create an environment using:
# $ conda create --name <env> --file <this file>
# platform: linux-64
_license=1.1=py35_1
anaconda-client=1.2.2=py35_0
click=6.3=py35_0
clyent=1.2.1=py35_0
conda=4.0.5=py35_0
conda-env=2.4.5=py35_0
cycler=0.10.0=py35_0
decorator=4.0.9=py35_0
fontconfig=2.11.1=5
freetype=2.5.5=0
gitdb=0.6.4=py35_0
gitpython=1.0.1=py35_0
historydict=1.0.0.post24=24_g6193dc2_py35
ipykernel=4.2.2=py35_0
ipython=4.1.1=py35_0
ipython_genutils=0.1.0=py35_0
ipywidgets=4.1.1=py35_0
jbig=2.1=0
jinja2=2.8=py35_0
jpeg=8d=0
jsonschema=2.4.0=py35_0
jupyter=1.0.0=py35_1
jupyter_client=4.1.1=py35_0
jupyter_console=4.1.0=py35_0
jupyter_core=4.0.6=py35_0
libgfortran=3.0=0
libpng=1.6.17=0
libsodium=1.0.3=0
libtiff=4.0.6=1
libxml2=2.9.2=0
markupsafe=0.23=py35_0
matplotlib=1.5.1.post61=61_g513da02_py35
mistune=0.7.1=py35_0
mkl=11.3.1=0
nbconvert=4.1.0=py35_0
nbformat=4.0.1=py35_0
ncurses=5.9=8
networkx=1.11=py35_0
notebook=4.1.0=py35_0
numpy=1.10.4=py35_1
openssl=1.0.2g=0
patchelf=0.8=0
path.py=8.1.2=py35_1
pexpect=3.3=py35_0
pickleshare=0.5=py35_0
pillow=2.9.0=py35_0
pims=0.3.3=py35_1
pip=8.1.0=py35_0
ptyprocess=0.5=py35_0
pycosat=0.6.1=py35_0
pycrypto=2.6.1=py35_0
pyflakes=1.1.0=py35_0
pygments=2.1.1=py35_0
pyparsing=2.0.3=py35_0
pyqt=4.11.4=py35_1
python=3.5.1=0
python-dateutil=2.4.2=py35_0
pytz=2015.7=py35_0
pyyaml=3.11=py35_1
pyzmq=15.2.0=py35_0
qt=4.8.7=1
qtconsole=4.1.1=py35_0
readline=6.2.5=1
requests=2.9.1=py35_0
scikit-image=0.12.3=np110py35_0
scipy=0.17.0=np110py35_2
setuptools=20.2.2=py35_0
simplegeneric=0.8.1=py35_0
sip=4.16.9=py35_0
six=1.10.0=py35_0
slicerator=0.9.7=py35_0
smmap=0.9.0=py35_0
sqlite=3.9.2=0
terminado=0.5=py35_1
tk=8.5.18=0
tornado=4.3=py35_0
traitlets=4.1.0=py35_0
wheel=0.29.0=py35_0
xz=5.0.5=1
yaml=0.1.6=0
zeromq=4.1.3=0
zlib=1.2.8=0
```



Discussion:
should be an easy fix. I'll have a PR tomorrow.

Thanks @ericdill for the report and @brentp for the quick response.  Let's make sure that one of our test cases has this kind of scenario so we don't hit this kind of regression again.  We can discuss on whatever PR @brentp puts forward.


Resolving patch:
diff --git a/conda_build/build.py b/conda_build/build.py
--- a/conda_build/build.py
+++ b/conda_build/build.py
@@ -107,6 +107,10 @@ def have_prefix_files(files):
             # skip symbolic links (as we can on Linux)
             continue
 
+        # dont try to mmap an empty file
+        if os.stat(path).st_size == 0:
+            continue
+
         fi = open(path, 'rb+')
         mm = mmap.mmap(fi.fileno(), 0)
 
diff --git a/conda_build/post.py b/conda_build/post.py
--- a/conda_build/post.py
+++ b/conda_build/post.py
@@ -46,6 +46,9 @@ def fix_shebang(f, osx_is_app=False):
     elif os.path.islink(path):
         return
 
+    if os.stat(path).st_size == 0:
+        return
+
     with io.open(path, encoding=locale.getpreferredencoding(), mode='r+') as fi:
         try:
             data = fi.read(100)


Test patch:
diff --git a/tests/test-recipes/test-package/conda_build_test/empty.py b/tests/test-recipes/test-package/conda_build_test/empty.py
new file mode 100644