We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
conda-build crashes when building PEP420 namespace packages
There is a very trivial bug in `conda_build.utils.copy_into()`, causing it to crash when building PEP420 namespace packages. To reproduce the issue, all of the following conditions must be met:
- your package must be a native PEP420 namespace package (`python >=3.3`)
- your package must depend on (and therefore install) other packages mapping to the same namespace
- you must build all of these packages with `recipe['build']['preserve_egg_dir'] = False`
- your namespace must be a multi-level directory 

This is easier to explain by example:

```
found egg dir: C:\ANACONDA\envs\_build\Lib\site-packages\example-4.3.0-py3.5-win-amd64.egg
...
Traceback (most recent call last):
  File "C:\ANACONDA\Scripts\conda-build-script.py", line 4, in <module>
    sys.exit(main())
  File "C:\ANACONDA\lib\site-packages\conda_build\main_build.py", line 144, in main
    args_func(args, p)
  File "C:\ANACONDA\lib\site-packages\conda_build\main_build.py", line 389, in args_func
    args.func(args, p)
  File "C:\ANACONDA\lib\site-packages\conda_build\main_build.py", line 332, in execute
    dirty=args.dirty, activate=args.activate)
  File "C:\ANACONDA\lib\site-packages\conda_build\build.py", line 606, in build
    preserve_egg_dir=bool(m.get_value('build/preserve_egg_dir')))
  File "C:\ANACONDA\lib\site-packages\conda_build\post.py", line 162, in post_process
    remove_easy_install_pth(files, preserve_egg_dir=preserve_egg_dir)
  File "C:\ANACONDA\lib\site-packages\conda_build\post.py", line 119, in remove_easy_install_pth
    utils.copy_into(join(egg_path, fn), join(sp_dir, fn))
  File "C:\ANACONDA\lib\site-packages\conda_build\utils.py", line 54, in copy_into
    shutil.copytree(srcname, dstname)
  File "C:\ANACONDA\lib\shutil.py", line 177, in copytree
    os.makedirs(dst)
  File "C:\ANACONDA\lib\os.py", line 157, in makedirs
    mkdir(name, mode)
WindowsError: [Error 183] Cannot create a file when that file already exists: 'C:\ANACONDA\envs\_build\Lib\site-packages\ns\sub'
```

Here `ns` is the top level namespace directory and `sub` is a sub-package, but also a namespace package:

```
+ ns
   |
   + sub
       |
       module.py
```

The problem is that conda is trying to copy `ns\sub` to site-packages at build time. However, this directory already exists because another package -- a runtime dependency -- is already installed in site packages providing the same namespace directory layout:

```
+ ns
   |
   + sub
       |
       dependency.py
```

`conda-build` needs to be able to "merge" the `sub` directories coming from all namespace packages. Deleting or skipping directories if they exist will corrupt the namespace and produce incorrect results. Here is the quickest way to fix this:

``` python
from distutils.dir_util import copy_tree

def copy_into(src, dst):
    "Copy all the files and directories in src to the directory dst"

    if not isdir(src):
        tocopy = [src]
    else:
        tocopy = os.listdir(src)
    for afile in tocopy:
        srcname = os.path.join(src, afile)
        dstname = os.path.join(dst, afile)

        if os.path.isdir(srcname):
            copy_tree(srcname, dstname)
        else:
            shutil.copy2(srcname, dstname)
```

i.e. just replace `shutil.copytree()` with `distutils.dir_util.copy_tree()`.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `conda_build/utils.py`
Content:
```
1 from __future__ import absolute_import, division, print_function
2 
3 import fnmatch
4 import os
5 import sys
6 import shutil
7 import tarfile
8 import zipfile
9 import subprocess
10 import operator
11 from os.path import dirname, getmtime, getsize, isdir, join
12 from collections import defaultdict
13 
14 from conda.utils import md5_file, unix_path_to_win
15 from conda.compat import PY3, iteritems
16 
17 from conda_build import external
18 
19 # Backwards compatibility import. Do not remove.
20 from conda.install import rm_rf
21 rm_rf
22 
23 
24 def find_recipe(path):
25     """recurse through a folder, locating meta.yaml.  Raises error if more than one is found.
26 
27     Returns folder containing meta.yaml, to be built.
28 
29     If we have a base level meta.yaml and other supplemental ones, use that first"""
30     results = rec_glob(path, ["meta.yaml", "conda.yaml"])
31     if len(results) > 1:
32         base_recipe = os.path.join(path, "meta.yaml")
33         if base_recipe in results:
34             return os.path.dirname(base_recipe)
35         else:
36             raise IOError("More than one meta.yaml files found in %s" % path)
37     elif not results:
38         raise IOError("No meta.yaml files found in %s" % path)
39     return os.path.dirname(results[0])
40 
41 
42 def copy_into(src, dst):
43     "Copy all the files and directories in src to the directory dst"
44 
45     if not isdir(src):
46         tocopy = [src]
47     else:
48         tocopy = os.listdir(src)
49     for afile in tocopy:
50         srcname = os.path.join(src, afile)
51         dstname = os.path.join(dst, afile)
52 
53         if os.path.isdir(srcname):
54             shutil.copytree(srcname, dstname)
55         else:
56             shutil.copy2(srcname, dstname)
57 
58 
59 def relative(f, d='lib'):
60     assert not f.startswith('/'), f
61     assert not d.startswith('/'), d
62     d = d.strip('/').split('/')
63     if d == ['.']:
64         d = []
65     f = dirname(f).split('/')
66     if f == ['']:
67         f = []
68     while d and f and d[0] == f[0]:
69         d.pop(0)
70         f.pop(0)
71     return '/'.join(((['..'] * len(f)) if f else ['.']) + d)
72 
73 
74 def _check_call(args, **kwargs):
75     try:
76         subprocess.check_call(args, **kwargs)
77     except subprocess.CalledProcessError:
78         sys.exit('Command failed: %s' % ' '.join(args))
79 
80 
81 def tar_xf(tarball, dir_path, mode='r:*'):
82     if tarball.lower().endswith('.tar.z'):
83         uncompress = external.find_executable('uncompress')
84         if not uncompress:
85             uncompress = external.find_executable('gunzip')
86         if not uncompress:
87             sys.exit("""\
88 uncompress (or gunzip) is required to unarchive .z source files.
89 """)
90         subprocess.check_call([uncompress, '-f', tarball])
91         tarball = tarball[:-2]
92     if not PY3 and tarball.endswith('.tar.xz'):
93         unxz = external.find_executable('unxz')
94         if not unxz:
95             sys.exit("""\
96 unxz is required to unarchive .xz source files.
97 """)
98 
99         subprocess.check_call([unxz, '-f', '-k', tarball])
100         tarball = tarball[:-3]
101     t = tarfile.open(tarball, mode)
102     t.extractall(path=dir_path)
103     t.close()
104 
105 
106 def unzip(zip_path, dir_path):
107     z = zipfile.ZipFile(zip_path)
108     for name in z.namelist():
109         if name.endswith('/'):
110             continue
111         path = join(dir_path, *name.split('/'))
112         dp = dirname(path)
113         if not isdir(dp):
114             os.makedirs(dp)
115         with open(path, 'wb') as fo:
116             fo.write(z.read(name))
117     z.close()
118 
119 
120 def file_info(path):
121     return {'size': getsize(path),
122             'md5': md5_file(path),
123             'mtime': getmtime(path)}
124 
125 # Taken from toolz
126 
127 
128 def groupby(key, seq):
129     """ Group a collection by a key function
130     >>> names = ['Alice', 'Bob', 'Charlie', 'Dan', 'Edith', 'Frank']
131     >>> groupby(len, names)  # doctest: +SKIP
132     {3: ['Bob', 'Dan'], 5: ['Alice', 'Edith', 'Frank'], 7: ['Charlie']}
133     >>> iseven = lambda x: x % 2 == 0
134     >>> groupby(iseven, [1, 2, 3, 4, 5, 6, 7, 8])  # doctest: +SKIP
135     {False: [1, 3, 5, 7], True: [2, 4, 6, 8]}
136     Non-callable keys imply grouping on a member.
137     >>> groupby('gender', [{'name': 'Alice', 'gender': 'F'},
138     ...                    {'name': 'Bob', 'gender': 'M'},
139     ...                    {'name': 'Charlie', 'gender': 'M'}]) # doctest:+SKIP
140     {'F': [{'gender': 'F', 'name': 'Alice'}],
141      'M': [{'gender': 'M', 'name': 'Bob'},
142            {'gender': 'M', 'name': 'Charlie'}]}
143     See Also:
144         countby
145     """
146     if not callable(key):
147         key = getter(key)
148     d = defaultdict(lambda: [].append)
149     for item in seq:
150         d[key(item)](item)
151     rv = {}
152     for k, v in iteritems(d):
153         rv[k] = v.__self__
154     return rv
155 
156 
157 def getter(index):
158     if isinstance(index, list):
159         if len(index) == 1:
160             index = index[0]
161             return lambda x: (x[index],)
162         elif index:
163             return operator.itemgetter(*index)
164         else:
165             return lambda x: ()
166     else:
167         return operator.itemgetter(index)
168 
169 
170 def comma_join(items):
171     """
172     Like ', '.join(items) but with and
173 
174     Examples:
175 
176     >>> comma_join(['a'])
177     'a'
178     >>> comma_join(['a', 'b'])
179     'a and b'
180     >>> comma_join(['a', 'b', 'c])
181     'a, b, and c'
182     """
183     return ' and '.join(items) if len(items) <= 2 else ', '.join(items[:-1]) + ', and ' + items[-1]
184 
185 
186 def safe_print_unicode(*args, **kwargs):
187     """
188     prints unicode strings to stdout using configurable `errors` handler for
189     encoding errors
190 
191     :param args: unicode strings to print to stdout
192     :param sep: separator (defaults to ' ')
193     :param end: ending character (defaults to '\n')
194     :param errors: error handler for encoding errors (defaults to 'replace')
195     """
196     sep = kwargs.pop('sep', u' ')
197     end = kwargs.pop('end', u'\n')
198     errors = kwargs.pop('errors', 'replace')
199     if PY3:
200         func = sys.stdout.buffer.write
201     else:
202         func = sys.stdout.write
203     line = sep.join(args) + end
204     encoding = sys.stdout.encoding or 'utf8'
205     func(line.encode(encoding, errors))
206 
207 
208 def rec_glob(path, patterns):
209     result = []
210     for d_f in os.walk(path):
211         m = []
212         for pattern in patterns:
213             m.extend(fnmatch.filter(d_f[2], pattern))
214         if m:
215             result.extend([os.path.join(d_f[0], f) for f in m])
216     return result
217 
218 
219 def convert_unix_path_to_win(path):
220     if external.find_executable('cygpath'):
221         cmd = "cygpath -w {0}".format(path)
222         if PY3:
223             path = subprocess.getoutput(cmd)
224         else:
225             path = subprocess.check_output(cmd.split()).rstrip().rstrip("\\")
226 
227     else:
228         path = unix_path_to_win(path)
229     return path
230
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/conda_build/utils.py b/conda_build/utils.py
--- a/conda_build/utils.py
+++ b/conda_build/utils.py
@@ -8,8 +8,9 @@
 import zipfile
 import subprocess
 import operator
-from os.path import dirname, getmtime, getsize, isdir, join
+from os.path import dirname, getmtime, getsize, isdir, isfile, join
 from collections import defaultdict
+from distutils.dir_util import copy_tree
 
 from conda.utils import md5_file, unix_path_to_win
 from conda.compat import PY3, iteritems
@@ -51,11 +52,29 @@
         dstname = os.path.join(dst, afile)
 
         if os.path.isdir(srcname):
-            shutil.copytree(srcname, dstname)
+            merge_tree(srcname, dstname)
         else:
             shutil.copy2(srcname, dstname)
 
 
+def merge_tree(src, dst):
+    """
+    Merge src into dst recursively by copying all files from src into dst.
+    Return a list of all files copied.
+
+    Like copy_tree(src, dst), but raises an error if merging the two trees
+    would overwrite any files.
+    """
+    new_files = copy_tree(src, dst, dry_run=True)
+    existing = [f for f in new_files if isfile(f)]
+
+    if existing:
+        raise IOError("Can't merge {0} into {1}: file exists: "
+                      "{2}".format(src, dst, existing[0]))
+
+    return copy_tree(src, dst)
+
+
 def relative(f, d='lib'):
     assert not f.startswith('/'), f
     assert not d.startswith('/'), d

{"golden_diff": "diff --git a/conda_build/utils.py b/conda_build/utils.py\n--- a/conda_build/utils.py\n+++ b/conda_build/utils.py\n@@ -8,8 +8,9 @@\n import zipfile\n import subprocess\n import operator\n-from os.path import dirname, getmtime, getsize, isdir, join\n+from os.path import dirname, getmtime, getsize, isdir, isfile, join\n from collections import defaultdict\n+from distutils.dir_util import copy_tree\n \n from conda.utils import md5_file, unix_path_to_win\n from conda.compat import PY3, iteritems\n@@ -51,11 +52,29 @@\n         dstname = os.path.join(dst, afile)\n \n         if os.path.isdir(srcname):\n-            shutil.copytree(srcname, dstname)\n+            merge_tree(srcname, dstname)\n         else:\n             shutil.copy2(srcname, dstname)\n \n \n+def merge_tree(src, dst):\n+    \"\"\"\n+    Merge src into dst recursively by copying all files from src into dst.\n+    Return a list of all files copied.\n+\n+    Like copy_tree(src, dst), but raises an error if merging the two trees\n+    would overwrite any files.\n+    \"\"\"\n+    new_files = copy_tree(src, dst, dry_run=True)\n+    existing = [f for f in new_files if isfile(f)]\n+\n+    if existing:\n+        raise IOError(\"Can't merge {0} into {1}: file exists: \"\n+                      \"{2}\".format(src, dst, existing[0]))\n+\n+    return copy_tree(src, dst)\n+\n+\n def relative(f, d='lib'):\n     assert not f.startswith('/'), f\n     assert not d.startswith('/'), d\n", "issue": "conda-build crashes when building PEP420 namespace packages\nThere is a very trivial bug in `conda_build.utils.copy_into()`, causing it to crash when building PEP420 namespace packages. To reproduce the issue, all of the following conditions must be met:\n- your package must be a native PEP420 namespace package (`python >=3.3`)\n- your package must depend on (and therefore install) other packages mapping to the same namespace\n- you must build all of these packages with `recipe['build']['preserve_egg_dir'] = False`\n- your namespace must be a multi-level directory \n\nThis is easier to explain by example:\n\n```\nfound egg dir: C:\\ANACONDA\\envs\\_build\\Lib\\site-packages\\example-4.3.0-py3.5-win-amd64.egg\n...\nTraceback (most recent call last):\n  File \"C:\\ANACONDA\\Scripts\\conda-build-script.py\", line 4, in <module>\n    sys.exit(main())\n  File \"C:\\ANACONDA\\lib\\site-packages\\conda_build\\main_build.py\", line 144, in main\n    args_func(args, p)\n  File \"C:\\ANACONDA\\lib\\site-packages\\conda_build\\main_build.py\", line 389, in args_func\n    args.func(args, p)\n  File \"C:\\ANACONDA\\lib\\site-packages\\conda_build\\main_build.py\", line 332, in execute\n    dirty=args.dirty, activate=args.activate)\n  File \"C:\\ANACONDA\\lib\\site-packages\\conda_build\\build.py\", line 606, in build\n    preserve_egg_dir=bool(m.get_value('build/preserve_egg_dir')))\n  File \"C:\\ANACONDA\\lib\\site-packages\\conda_build\\post.py\", line 162, in post_process\n    remove_easy_install_pth(files, preserve_egg_dir=preserve_egg_dir)\n  File \"C:\\ANACONDA\\lib\\site-packages\\conda_build\\post.py\", line 119, in remove_easy_install_pth\n    utils.copy_into(join(egg_path, fn), join(sp_dir, fn))\n  File \"C:\\ANACONDA\\lib\\site-packages\\conda_build\\utils.py\", line 54, in copy_into\n    shutil.copytree(srcname, dstname)\n  File \"C:\\ANACONDA\\lib\\shutil.py\", line 177, in copytree\n    os.makedirs(dst)\n  File \"C:\\ANACONDA\\lib\\os.py\", line 157, in makedirs\n    mkdir(name, mode)\nWindowsError: [Error 183] Cannot create a file when that file already exists: 'C:\\ANACONDA\\envs\\_build\\Lib\\site-packages\\ns\\sub'\n```\n\nHere `ns` is the top level namespace directory and `sub` is a sub-package, but also a namespace package:\n\n```\n+ ns\n   |\n   + sub\n       |\n       module.py\n```\n\nThe problem is that conda is trying to copy `ns\\sub` to site-packages at build time. However, this directory already exists because another package -- a runtime dependency -- is already installed in site packages providing the same namespace directory layout:\n\n```\n+ ns\n   |\n   + sub\n       |\n       dependency.py\n```\n\n`conda-build` needs to be able to \"merge\" the `sub` directories coming from all namespace packages. Deleting or skipping directories if they exist will corrupt the namespace and produce incorrect results. Here is the quickest way to fix this:\n\n``` python\nfrom distutils.dir_util import copy_tree\n\ndef copy_into(src, dst):\n    \"Copy all the files and directories in src to the directory dst\"\n\n    if not isdir(src):\n        tocopy = [src]\n    else:\n        tocopy = os.listdir(src)\n    for afile in tocopy:\n        srcname = os.path.join(src, afile)\n        dstname = os.path.join(dst, afile)\n\n        if os.path.isdir(srcname):\n            copy_tree(srcname, dstname)\n        else:\n            shutil.copy2(srcname, dstname)\n```\n\ni.e. just replace `shutil.copytree()` with `distutils.dir_util.copy_tree()`.\n\n", "before_files": [{"content": "from __future__ import absolute_import, division, print_function\n\nimport fnmatch\nimport os\nimport sys\nimport shutil\nimport tarfile\nimport zipfile\nimport subprocess\nimport operator\nfrom os.path import dirname, getmtime, getsize, isdir, join\nfrom collections import defaultdict\n\nfrom conda.utils import md5_file, unix_path_to_win\nfrom conda.compat import PY3, iteritems\n\nfrom conda_build import external\n\n# Backwards compatibility import. Do not remove.\nfrom conda.install import rm_rf\nrm_rf\n\n\ndef find_recipe(path):\n    \"\"\"recurse through a folder, locating meta.yaml.  Raises error if more than one is found.\n\n    Returns folder containing meta.yaml, to be built.\n\n    If we have a base level meta.yaml and other supplemental ones, use that first\"\"\"\n    results = rec_glob(path, [\"meta.yaml\", \"conda.yaml\"])\n    if len(results) > 1:\n        base_recipe = os.path.join(path, \"meta.yaml\")\n        if base_recipe in results:\n            return os.path.dirname(base_recipe)\n        else:\n            raise IOError(\"More than one meta.yaml files found in %s\" % path)\n    elif not results:\n        raise IOError(\"No meta.yaml files found in %s\" % path)\n    return os.path.dirname(results[0])\n\n\ndef copy_into(src, dst):\n    \"Copy all the files and directories in src to the directory dst\"\n\n    if not isdir(src):\n        tocopy = [src]\n    else:\n        tocopy = os.listdir(src)\n    for afile in tocopy:\n        srcname = os.path.join(src, afile)\n        dstname = os.path.join(dst, afile)\n\n        if os.path.isdir(srcname):\n            shutil.copytree(srcname, dstname)\n        else:\n            shutil.copy2(srcname, dstname)\n\n\ndef relative(f, d='lib'):\n    assert not f.startswith('/'), f\n    assert not d.startswith('/'), d\n    d = d.strip('/').split('/')\n    if d == ['.']:\n        d = []\n    f = dirname(f).split('/')\n    if f == ['']:\n        f = []\n    while d and f and d[0] == f[0]:\n        d.pop(0)\n        f.pop(0)\n    return '/'.join(((['..'] * len(f)) if f else ['.']) + d)\n\n\ndef _check_call(args, **kwargs):\n    try:\n        subprocess.check_call(args, **kwargs)\n    except subprocess.CalledProcessError:\n        sys.exit('Command failed: %s' % ' '.join(args))\n\n\ndef tar_xf(tarball, dir_path, mode='r:*'):\n    if tarball.lower().endswith('.tar.z'):\n        uncompress = external.find_executable('uncompress')\n        if not uncompress:\n            uncompress = external.find_executable('gunzip')\n        if not uncompress:\n            sys.exit(\"\"\"\\\nuncompress (or gunzip) is required to unarchive .z source files.\n\"\"\")\n        subprocess.check_call([uncompress, '-f', tarball])\n        tarball = tarball[:-2]\n    if not PY3 and tarball.endswith('.tar.xz'):\n        unxz = external.find_executable('unxz')\n        if not unxz:\n            sys.exit(\"\"\"\\\nunxz is required to unarchive .xz source files.\n\"\"\")\n\n        subprocess.check_call([unxz, '-f', '-k', tarball])\n        tarball = tarball[:-3]\n    t = tarfile.open(tarball, mode)\n    t.extractall(path=dir_path)\n    t.close()\n\n\ndef unzip(zip_path, dir_path):\n    z = zipfile.ZipFile(zip_path)\n    for name in z.namelist():\n        if name.endswith('/'):\n            continue\n        path = join(dir_path, *name.split('/'))\n        dp = dirname(path)\n        if not isdir(dp):\n            os.makedirs(dp)\n        with open(path, 'wb') as fo:\n            fo.write(z.read(name))\n    z.close()\n\n\ndef file_info(path):\n    return {'size': getsize(path),\n            'md5': md5_file(path),\n            'mtime': getmtime(path)}\n\n# Taken from toolz\n\n\ndef groupby(key, seq):\n    \"\"\" Group a collection by a key function\n    >>> names = ['Alice', 'Bob', 'Charlie', 'Dan', 'Edith', 'Frank']\n    >>> groupby(len, names)  # doctest: +SKIP\n    {3: ['Bob', 'Dan'], 5: ['Alice', 'Edith', 'Frank'], 7: ['Charlie']}\n    >>> iseven = lambda x: x % 2 == 0\n    >>> groupby(iseven, [1, 2, 3, 4, 5, 6, 7, 8])  # doctest: +SKIP\n    {False: [1, 3, 5, 7], True: [2, 4, 6, 8]}\n    Non-callable keys imply grouping on a member.\n    >>> groupby('gender', [{'name': 'Alice', 'gender': 'F'},\n    ...                    {'name': 'Bob', 'gender': 'M'},\n    ...                    {'name': 'Charlie', 'gender': 'M'}]) # doctest:+SKIP\n    {'F': [{'gender': 'F', 'name': 'Alice'}],\n     'M': [{'gender': 'M', 'name': 'Bob'},\n           {'gender': 'M', 'name': 'Charlie'}]}\n    See Also:\n        countby\n    \"\"\"\n    if not callable(key):\n        key = getter(key)\n    d = defaultdict(lambda: [].append)\n    for item in seq:\n        d[key(item)](item)\n    rv = {}\n    for k, v in iteritems(d):\n        rv[k] = v.__self__\n    return rv\n\n\ndef getter(index):\n    if isinstance(index, list):\n        if len(index) == 1:\n            index = index[0]\n            return lambda x: (x[index],)\n        elif index:\n            return operator.itemgetter(*index)\n        else:\n            return lambda x: ()\n    else:\n        return operator.itemgetter(index)\n\n\ndef comma_join(items):\n    \"\"\"\n    Like ', '.join(items) but with and\n\n    Examples:\n\n    >>> comma_join(['a'])\n    'a'\n    >>> comma_join(['a', 'b'])\n    'a and b'\n    >>> comma_join(['a', 'b', 'c])\n    'a, b, and c'\n    \"\"\"\n    return ' and '.join(items) if len(items) <= 2 else ', '.join(items[:-1]) + ', and ' + items[-1]\n\n\ndef safe_print_unicode(*args, **kwargs):\n    \"\"\"\n    prints unicode strings to stdout using configurable `errors` handler for\n    encoding errors\n\n    :param args: unicode strings to print to stdout\n    :param sep: separator (defaults to ' ')\n    :param end: ending character (defaults to '\\n')\n    :param errors: error handler for encoding errors (defaults to 'replace')\n    \"\"\"\n    sep = kwargs.pop('sep', u' ')\n    end = kwargs.pop('end', u'\\n')\n    errors = kwargs.pop('errors', 'replace')\n    if PY3:\n        func = sys.stdout.buffer.write\n    else:\n        func = sys.stdout.write\n    line = sep.join(args) + end\n    encoding = sys.stdout.encoding or 'utf8'\n    func(line.encode(encoding, errors))\n\n\ndef rec_glob(path, patterns):\n    result = []\n    for d_f in os.walk(path):\n        m = []\n        for pattern in patterns:\n            m.extend(fnmatch.filter(d_f[2], pattern))\n        if m:\n            result.extend([os.path.join(d_f[0], f) for f in m])\n    return result\n\n\ndef convert_unix_path_to_win(path):\n    if external.find_executable('cygpath'):\n        cmd = \"cygpath -w {0}\".format(path)\n        if PY3:\n            path = subprocess.getoutput(cmd)\n        else:\n            path = subprocess.check_output(cmd.split()).rstrip().rstrip(\"\\\\\")\n\n    else:\n        path = unix_path_to_win(path)\n    return path\n", "path": "conda_build/utils.py"}], "after_files": [{"content": "from __future__ import absolute_import, division, print_function\n\nimport fnmatch\nimport os\nimport sys\nimport shutil\nimport tarfile\nimport zipfile\nimport subprocess\nimport operator\nfrom os.path import dirname, getmtime, getsize, isdir, isfile, join\nfrom collections import defaultdict\nfrom distutils.dir_util import copy_tree\n\nfrom conda.utils import md5_file, unix_path_to_win\nfrom conda.compat import PY3, iteritems\n\nfrom conda_build import external\n\n# Backwards compatibility import. Do not remove.\nfrom conda.install import rm_rf\nrm_rf\n\n\ndef find_recipe(path):\n    \"\"\"recurse through a folder, locating meta.yaml.  Raises error if more than one is found.\n\n    Returns folder containing meta.yaml, to be built.\n\n    If we have a base level meta.yaml and other supplemental ones, use that first\"\"\"\n    results = rec_glob(path, [\"meta.yaml\", \"conda.yaml\"])\n    if len(results) > 1:\n        base_recipe = os.path.join(path, \"meta.yaml\")\n        if base_recipe in results:\n            return os.path.dirname(base_recipe)\n        else:\n            raise IOError(\"More than one meta.yaml files found in %s\" % path)\n    elif not results:\n        raise IOError(\"No meta.yaml files found in %s\" % path)\n    return os.path.dirname(results[0])\n\n\ndef copy_into(src, dst):\n    \"Copy all the files and directories in src to the directory dst\"\n\n    if not isdir(src):\n        tocopy = [src]\n    else:\n        tocopy = os.listdir(src)\n    for afile in tocopy:\n        srcname = os.path.join(src, afile)\n        dstname = os.path.join(dst, afile)\n\n        if os.path.isdir(srcname):\n            merge_tree(srcname, dstname)\n        else:\n            shutil.copy2(srcname, dstname)\n\n\ndef merge_tree(src, dst):\n    \"\"\"\n    Merge src into dst recursively by copying all files from src into dst.\n    Return a list of all files copied.\n\n    Like copy_tree(src, dst), but raises an error if merging the two trees\n    would overwrite any files.\n    \"\"\"\n    new_files = copy_tree(src, dst, dry_run=True)\n    existing = [f for f in new_files if isfile(f)]\n\n    if existing:\n        raise IOError(\"Can't merge {0} into {1}: file exists: \"\n                      \"{2}\".format(src, dst, existing[0]))\n\n    return copy_tree(src, dst)\n\n\ndef relative(f, d='lib'):\n    assert not f.startswith('/'), f\n    assert not d.startswith('/'), d\n    d = d.strip('/').split('/')\n    if d == ['.']:\n        d = []\n    f = dirname(f).split('/')\n    if f == ['']:\n        f = []\n    while d and f and d[0] == f[0]:\n        d.pop(0)\n        f.pop(0)\n    return '/'.join(((['..'] * len(f)) if f else ['.']) + d)\n\n\ndef _check_call(args, **kwargs):\n    try:\n        subprocess.check_call(args, **kwargs)\n    except subprocess.CalledProcessError:\n        sys.exit('Command failed: %s' % ' '.join(args))\n\n\ndef tar_xf(tarball, dir_path, mode='r:*'):\n    if tarball.lower().endswith('.tar.z'):\n        uncompress = external.find_executable('uncompress')\n        if not uncompress:\n            uncompress = external.find_executable('gunzip')\n        if not uncompress:\n            sys.exit(\"\"\"\\\nuncompress (or gunzip) is required to unarchive .z source files.\n\"\"\")\n        subprocess.check_call([uncompress, '-f', tarball])\n        tarball = tarball[:-2]\n    if not PY3 and tarball.endswith('.tar.xz'):\n        unxz = external.find_executable('unxz')\n        if not unxz:\n            sys.exit(\"\"\"\\\nunxz is required to unarchive .xz source files.\n\"\"\")\n\n        subprocess.check_call([unxz, '-f', '-k', tarball])\n        tarball = tarball[:-3]\n    t = tarfile.open(tarball, mode)\n    t.extractall(path=dir_path)\n    t.close()\n\n\ndef unzip(zip_path, dir_path):\n    z = zipfile.ZipFile(zip_path)\n    for name in z.namelist():\n        if name.endswith('/'):\n            continue\n        path = join(dir_path, *name.split('/'))\n        dp = dirname(path)\n        if not isdir(dp):\n            os.makedirs(dp)\n        with open(path, 'wb') as fo:\n            fo.write(z.read(name))\n    z.close()\n\n\ndef file_info(path):\n    return {'size': getsize(path),\n            'md5': md5_file(path),\n            'mtime': getmtime(path)}\n\n# Taken from toolz\n\n\ndef groupby(key, seq):\n    \"\"\" Group a collection by a key function\n    >>> names = ['Alice', 'Bob', 'Charlie', 'Dan', 'Edith', 'Frank']\n    >>> groupby(len, names)  # doctest: +SKIP\n    {3: ['Bob', 'Dan'], 5: ['Alice', 'Edith', 'Frank'], 7: ['Charlie']}\n    >>> iseven = lambda x: x % 2 == 0\n    >>> groupby(iseven, [1, 2, 3, 4, 5, 6, 7, 8])  # doctest: +SKIP\n    {False: [1, 3, 5, 7], True: [2, 4, 6, 8]}\n    Non-callable keys imply grouping on a member.\n    >>> groupby('gender', [{'name': 'Alice', 'gender': 'F'},\n    ...                    {'name': 'Bob', 'gender': 'M'},\n    ...                    {'name': 'Charlie', 'gender': 'M'}]) # doctest:+SKIP\n    {'F': [{'gender': 'F', 'name': 'Alice'}],\n     'M': [{'gender': 'M', 'name': 'Bob'},\n           {'gender': 'M', 'name': 'Charlie'}]}\n    See Also:\n        countby\n    \"\"\"\n    if not callable(key):\n        key = getter(key)\n    d = defaultdict(lambda: [].append)\n    for item in seq:\n        d[key(item)](item)\n    rv = {}\n    for k, v in iteritems(d):\n        rv[k] = v.__self__\n    return rv\n\n\ndef getter(index):\n    if isinstance(index, list):\n        if len(index) == 1:\n            index = index[0]\n            return lambda x: (x[index],)\n        elif index:\n            return operator.itemgetter(*index)\n        else:\n            return lambda x: ()\n    else:\n        return operator.itemgetter(index)\n\n\ndef comma_join(items):\n    \"\"\"\n    Like ', '.join(items) but with and\n\n    Examples:\n\n    >>> comma_join(['a'])\n    'a'\n    >>> comma_join(['a', 'b'])\n    'a and b'\n    >>> comma_join(['a', 'b', 'c])\n    'a, b, and c'\n    \"\"\"\n    return ' and '.join(items) if len(items) <= 2 else ', '.join(items[:-1]) + ', and ' + items[-1]\n\n\ndef safe_print_unicode(*args, **kwargs):\n    \"\"\"\n    prints unicode strings to stdout using configurable `errors` handler for\n    encoding errors\n\n    :param args: unicode strings to print to stdout\n    :param sep: separator (defaults to ' ')\n    :param end: ending character (defaults to '\\n')\n    :param errors: error handler for encoding errors (defaults to 'replace')\n    \"\"\"\n    sep = kwargs.pop('sep', u' ')\n    end = kwargs.pop('end', u'\\n')\n    errors = kwargs.pop('errors', 'replace')\n    if PY3:\n        func = sys.stdout.buffer.write\n    else:\n        func = sys.stdout.write\n    line = sep.join(args) + end\n    encoding = sys.stdout.encoding or 'utf8'\n    func(line.encode(encoding, errors))\n\n\ndef rec_glob(path, patterns):\n    result = []\n    for d_f in os.walk(path):\n        m = []\n        for pattern in patterns:\n            m.extend(fnmatch.filter(d_f[2], pattern))\n        if m:\n            result.extend([os.path.join(d_f[0], f) for f in m])\n    return result\n\n\ndef convert_unix_path_to_win(path):\n    if external.find_executable('cygpath'):\n        cmd = \"cygpath -w {0}\".format(path)\n        if PY3:\n            path = subprocess.getoutput(cmd)\n        else:\n            path = subprocess.check_output(cmd.split()).rstrip().rstrip(\"\\\\\")\n\n    else:\n        path = unix_path_to_win(path)\n    return path\n", "path": "conda_build/utils.py"}]}