Repository: conda/conda-build

Issue:
`conda index -s` fails with TypeError
### Expected Behavior

`conda index -s` should generate and/or update `index.html`, `repodata.json`, etc. in the target subdirectories.

### Actual Behavior

The application dies with the following error:
```
Traceback (most recent call last):
  File "/home/clee/.miniconda3-x86_64/bin/conda-index", line 11, in <module>
    sys.exit(main())
  File "/home/clee/.miniconda3-x86_64/lib/python3.6/site-packages/conda_build/cli/main_index.py", line 75, in main
    return execute(sys.argv[1:])
  File "/home/clee/.miniconda3-x86_64/lib/python3.6/site-packages/conda_build/cli/main_index.py", line 71, in execute
    verbose=args.verbose, progress=args.progress, hotfix_source_repo=args.hotfix_source_repo)
  File "/home/clee/.miniconda3-x86_64/lib/python3.6/site-packages/conda_build/api.py", line 386, in update_index
    threads=threads, verbose=verbose, progress=progress)
  File "/home/clee/.miniconda3-x86_64/lib/python3.6/site-packages/conda_build/index.py", line 251, in update_subdir_index
    subdir, verbose=verbose, progress=progress)
  File "/home/clee/.miniconda3-x86_64/lib/python3.6/site-packages/conda_build/index.py", line 850, in index_subdir
    subdir_path = join(self.channel_root, subdir)
  File "/home/clee/.miniconda3-x86_64/lib/python3.6/posixpath.py", line 94, in join
    genericpath._check_arg_types('join', a, *p)
  File "/home/clee/.miniconda3-x86_64/lib/python3.6/genericpath.py", line 149, in _check_arg_types
    (funcname, s.__class__.__name__)) from None
TypeError: join() argument must be str or bytes, not 'list'
```

### Steps to Reproduce

1. If needed, create the target subdirectories: `mkdir -p noarch linux-64`.
1. Run `conda index -s noarch -s linux-64` or `conda index -s noarch`.

Note that the same error also occurs for the non-empty directories.

### Output of `conda info`
<!-- Between the ticks below, paste the output of 'conda info' -->
```
     active environment : None
       user config file : /home/clee/.condarc
 populated config files : /home/clee/.condarc
          conda version : 4.5.11
    conda-build version : 3.15.1
         python version : 3.6.5.final.0
       base environment : /home/clee/.miniconda3-x86_64  (writable)
           channel URLs : https://repo.anaconda.com/pkgs/main/linux-64
                          https://repo.anaconda.com/pkgs/main/noarch
                          https://repo.anaconda.com/pkgs/free/linux-64
                          https://repo.anaconda.com/pkgs/free/noarch
                          https://repo.anaconda.com/pkgs/r/linux-64
                          https://repo.anaconda.com/pkgs/r/noarch
                          https://repo.anaconda.com/pkgs/pro/linux-64
                          https://repo.anaconda.com/pkgs/pro/noarch
          package cache : /home/clee/.miniconda3-x86_64/pkgs
                          /home/clee/.conda/pkgs
       envs directories : /home/clee/.miniconda3-x86_64/envs
                          /home/clee/.conda/envs
               platform : linux-64
             user-agent : conda/4.5.11 requests/2.18.4 CPython/3.6.5 Linux/4.15.0-34-generic ubuntu/18.04 glibc/2.27
                UID:GID : 7001:7000
             netrc file : None
           offline mode : False
```




Discussion:
The problem is with the -s (subdir) flag.  Just leave that off, and it will work fine (it will recurse through all your subdirs.)
Is the plan to remove support for indexing individual subdirectories? If so, please feel free to close this ticket.

(We ran across this issue because our CI system currently assumes `conda index`'s old behavior and indexes each subdirectory as builds for a platform complete. However, adapting our system to run `conda index` just once after _all_ platform builds are complete is pretty easy, so this is by no means a major issue.)
The support should be there, but it should be something of a speed optimization only, not commonly used.  This is a bug that needs to be fixed.

Resolving patch:
diff --git a/conda_build/api.py b/conda_build/api.py
--- a/conda_build/api.py
+++ b/conda_build/api.py
@@ -374,17 +374,15 @@ def update_index(dir_paths, config=None, force=False, check_md5=False, remove=Fa
     from locale import getpreferredencoding
     import os
     from .conda_interface import PY3
-    from conda_build.index import update_index, update_subdir_index
+    from conda_build.index import update_index
+    from conda_build.utils import ensure_list
     dir_paths = [os.path.abspath(path) for path in _ensure_list(dir_paths)]
     # Don't use byte strings in Python 2
     if not PY3:
         dir_paths = [path.decode(getpreferredencoding()) for path in dir_paths]
 
     for path in dir_paths:
-        if subdir:
-            update_subdir_index(path, subdir=subdir, check_md5=check_md5, channel_name=channel_name,
-                                threads=threads, verbose=verbose, progress=progress)
-        else:
-            update_index(path, check_md5=check_md5, channel_name=channel_name,
-                         patch_generator=patch_generator, threads=threads, verbose=verbose, progress=progress,
-                         hotfix_source_repo=hotfix_source_repo)
+        update_index(path, check_md5=check_md5, channel_name=channel_name,
+                     patch_generator=patch_generator, threads=threads, verbose=verbose,
+                     progress=progress, hotfix_source_repo=hotfix_source_repo,
+                     subdirs=ensure_list(subdir))
diff --git a/conda_build/index.py b/conda_build/index.py
--- a/conda_build/index.py
+++ b/conda_build/index.py
@@ -245,20 +245,8 @@ def _ensure_valid_channel(local_folder, subdir):
             os.makedirs(path)
 
 
-def update_subdir_index(dir_path, subdir, check_md5=False, channel_name=None, threads=None, verbose=False, progress=False):
-    """
-    Update all index files in dir_path with changed packages.
-
-    :param check_md5: Whether to check MD5s instead of mtimes for determining
-                      if a package changed.
-    :type check_md5: bool
-    """
-    return ChannelIndex(dir_path, channel_name, deep_integrity_check=check_md5, threads=threads).index_subdir(
-        subdir, verbose=verbose, progress=progress)
-
-
-def update_index(dir_path, check_md5=False, channel_name=None, patch_generator=None, threads=None, verbose=False,
-                 progress=False, hotfix_source_repo=None):
+def update_index(dir_path, check_md5=False, channel_name=None, patch_generator=None, threads=None,
+                 verbose=False, progress=False, hotfix_source_repo=None, subdirs=None):
     """
     If dir_path contains a directory named 'noarch', the path tree therein is treated
     as though it's a full channel, with a level of subdirs, each subdir having an update
@@ -273,10 +261,13 @@ def update_index(dir_path, check_md5=False, channel_name=None, patch_generator=N
     if dirname in DEFAULT_SUBDIRS:
         log.warn("The update_index function has changed to index all subdirs at once.  You're pointing it at a single subdir.  "
                  "Please update your code to point it at the channel root, rather than a subdir.")
-        return update_index(base_path, check_md5=check_md5, channel_name=channel_name, threads=threads,
-                            verbose=verbose, hotfix_source_repo=hotfix_source_repo)
-    return ChannelIndex(dir_path, channel_name, deep_integrity_check=check_md5, threads=threads).index(
-        patch_generator=patch_generator, verbose=verbose, progress=progress, hotfix_source_repo=hotfix_source_repo)
+        return update_index(base_path, check_md5=check_md5, channel_name=channel_name,
+                            threads=threads, verbose=verbose, progress=progress,
+                            hotfix_source_repo=hotfix_source_repo)
+    return ChannelIndex(dir_path, channel_name, subdirs=subdirs, deep_integrity_check=check_md5,
+                        threads=threads).index(patch_generator=patch_generator, verbose=verbose,
+                                               progress=progress,
+                                               hotfix_source_repo=hotfix_source_repo)
 
 
 def _determine_namespace(info):
@@ -852,7 +843,7 @@ def index(self, patch_generator, hotfix_source_repo=None, verbose=False, progres
             level = logging.ERROR
 
         with utils.LoggingContext(level, loggers=[__name__]):
-            if self._subdirs is None:
+            if not self._subdirs:
                 detected_subdirs = set(subdir for subdir in os.listdir(self.channel_root)
                                     if subdir in DEFAULT_SUBDIRS and isdir(join(self.channel_root, subdir)))
                 log.debug("found subdirs %s" % detected_subdirs)


Test patch: