Repository: conda/conda-build

Issue:
conda-skeleton --recursive should handle circular dependecies
```
$ conda skeleton pypi setuptools --recursive
More than one source version is available for setuptools:
Using url https://pypi.python.org/packages/source/s/setuptools/setuptools-15.2.tar.gz (613 KB) for setuptools.
Downloading setuptools (use --no-download to skip this step)
Using cached download
Unpacking setuptools...
done
working in /tmp/tmpbA7D_bconda_skeleton_setuptools-15.2.tar.gz
Fetching package metadata: ........
Solving package specifications: .
Applying patch: '/tmp/tmpbA7D_bconda_skeleton_setuptools-15.2.tar.gz/pypi-distutils.patch'
patching file core.py
Hunk #1 succeeded at 168 with fuzz 2 (offset 2 lines).
More than one source version is available for setuptools:
Using url https://pypi.python.org/packages/source/s/setuptools/setuptools-15.2.tar.gz (613 KB) for setuptools.
Downloading setuptools (use --no-download to skip this step)
Using cached download
Unpacking setuptools...
done
working in /tmp/tmpey4nw_conda_skeleton_setuptools-15.2.tar.gz
Solving package specifications: .
Applying patch: '/tmp/tmpey4nw_conda_skeleton_setuptools-15.2.tar.gz/pypi-distutils.patch'
patching file core.py
Hunk #1 succeeded at 168 with fuzz 2 (offset 2 lines).
More than one source version is available for setuptools:
Using url https://pypi.python.org/packages/source/s/setuptools/setuptools-15.2.tar.gz (613 KB) for setuptools.
Downloading setuptools (use --no-download to skip this step)
Using cached download
Unpacking setuptools...
done
working in /tmp/tmp3UrDHFconda_skeleton_setuptools-15.2.tar.gz
Solving package specifications: .
Applying patch: '/tmp/tmp3UrDHFconda_skeleton_setuptools-15.2.tar.gz/pypi-distutils.patch'
patching file core.py
Hunk #1 succeeded at 168 with fuzz 2 (offset 2 lines).
More than one source version is available for setuptools:
Using url https://pypi.python.org/packages/source/s/setuptools/setuptools-15.2.tar.gz (613 KB) for setuptools.
Downloading setuptools (use --no-download to skip this step)
Using cached download
Unpacking setuptools...
done
working in /tmp/tmp6dsPqiconda_skeleton_setuptools-15.2.tar.gz
Solving package specifications: .
Applying patch: '/tmp/tmp6dsPqiconda_skeleton_setuptools-15.2.tar.gz/pypi-distutils.patch'
patching file core.py
Hunk #1 succeeded at 168 with fuzz 2 (offset 2 lines).
More than one source version is available for setuptools:
Using url https://pypi.python.org/packages/source/s/setuptools/setuptools-15.2.tar.gz (613 KB) for setuptools.
Downloading setuptools (use --no-download to skip this step)
Using cached download
Unpacking setuptools...
done
working in /tmp/tmpxx_wB3conda_skeleton_setuptools-15.2.tar.gz
Solving package specifications: .
Applying patch: '/tmp/tmpxx_wB3conda_skeleton_setuptools-15.2.tar.gz/pypi-distutils.patch'
patching file core.py
Hunk #1 succeeded at 168 with fuzz 2 (offset 2 lines).
.
.
.
```



Discussion:
This is for the obvious reason that recipe created by `conda skeleton` for  `setuptools` has `setuptools` as a dependency, though this case appears one of a kind, we should probably check for circular dependencies with `--recursive` option.

But this issue is important because it also arises when I run `conda-skeleton --recursive` on a package which has stated `setuptools` as a dependency. Example: `jinja2` 

Found another case of circular dependency. The `sphnix` package depends on `sphinx_rtd_theme` and `sphix_rtd_theme` depends on `sphnix`, hence creating recipe for `sphinx` with `conda-skeleton --recursive` also goes in an infinite loop.

@asmeurer @ilanschnell any hints on solving this bug? I guess conda would have procedures to resolve circular dependencies, can you redirect me to them.

No, but it isn't hard. You just have to keep track of what recipes have been built and exit early without checking for dependencies if the same package is found twice. 


Resolving patch:
diff --git a/conda_build/pypi.py b/conda_build/pypi.py
--- a/conda_build/pypi.py
+++ b/conda_build/pypi.py
@@ -255,10 +255,12 @@ def main(args, parser):
     all_packages = client.list_packages()
     all_packages_lower = [i.lower() for i in all_packages]
 
+    args.created_recipes = []
     while args.packages:
         [output_dir] = args.output_dir
 
         package = args.packages.pop()
+        args.created_recipes.append(package)
 
         is_url = ':' in package
 
@@ -553,7 +555,8 @@ def get_package_metadata(args, package, d, data):
                 for dep in deps:
                     dep = dep.split()[0]
                     if not exists(join(output_dir, dep)):
-                        args.packages.append(dep)
+                        if dep not in args.created_recipes:
+                            args.packages.append(dep)
 
         if 'packagename' not in d:
             d['packagename'] = pkginfo['name'].lower()


Test patch: