Repository: conda/conda

Issue:
4.4+conda-build not prioritizing local channel correctly
I have a package, bzip2, build number 4, locally.  I'm expecting it to be used as a dependency.  Conda 4.3.31 finds it ok:

```
conda build libnetcdf-feedstock/
Adding in variants from internal_defaults
INFO:conda_build.variants:Adding in variants from internal_defaults
Adding in variants from /home/dev/code/aggregate/conda_build_config.yaml
INFO:conda_build.variants:Adding in variants from /home/dev/code/aggregate/conda_build_config.yaml
Attempting to finalize metadata for libnetcdf
INFO:conda_build.metadata:Attempting to finalize metadata for libnetcdf
BUILD START: ['libnetcdf-4.5.0-h569e9f1_6.tar.bz2']

The following NEW packages will be INSTALLED:

    bzip2:           1.0.6-h9a117a8_4      local
    ca-certificates: 2017.08.26-h1d4fec5_0 defaults
    curl:            7.55.1-h78862de_4     defaults
    hdf4:            4.2.13-h3ca952b_2     defaults
    hdf5:            1.8.18-h6792536_1     defaults
    jpeg:            9b-h024ee3a_2         defaults
    libgcc-ng:       7.2.0-h7cc24e2_2      defaults
    libgfortran-ng:  7.2.0-h9f7466a_2      defaults
    libssh2:         1.8.0-h2d05a93_3      defaults
    libstdcxx-ng:    7.2.0-h7a57d05_2      defaults
    openssl:         1.0.2n-hb7f436b_0     defaults
    zlib:            1.2.11-ha838bed_2     defaults
```

Conda 4.4.0 does not:

```
[root@69189185e23f aggregate]# conda build libnetcdf-feedstock/
Adding in variants from internal_defaults
INFO:conda_build.variants:Adding in variants from internal_defaults
Adding in variants from /home/dev/code/aggregate/conda_build_config.yaml
INFO:conda_build.variants:Adding in variants from /home/dev/code/aggregate/conda_build_config.yaml
Attempting to finalize metadata for libnetcdf
INFO:conda_build.metadata:Attempting to finalize metadata for libnetcdf
Solving environment: done
Solving environment: done
Solving environment: done
BUILD START: ['libnetcdf-4.5.0-h569e9f1_6.tar.bz2']
Solving environment: done

## Package Plan ##

  environment location: /opt/conda/conda-bld/libnetcdf_1513891848918/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_pla


The following NEW packages will be INSTALLED:

    bzip2:           1.0.6-3               defaults
    ca-certificates: 2017.08.26-h1d4fec5_0 defaults
    curl:            7.55.1-h78862de_4     defaults
    hdf4:            4.2.13-h3ca952b_2     defaults
    hdf5:            1.8.18-h6792536_1     defaults
    jpeg:            9b-h024ee3a_2         defaults
    libgcc-ng:       7.2.0-h7cc24e2_2      defaults
    libgfortran-ng:  7.2.0-h9f7466a_2      defaults
    libssh2:         1.8.0-h2d05a93_3      defaults
    libstdcxx-ng:    7.2.0-h7a57d05_2      defaults
    openssl:         1.0.2n-hb7f436b_0     defaults
    zlib:            1.2.11-ha838bed_2     defaults
```

This is conda-build 3.2.0, if that helps.


Discussion:
I've identified the issue.  Might take some discussion to figure out how to fix it.  Here's the issue...

The `install_actions()` function in conda takes a `channel_priority_map` parameter:
https://github.com/conda/conda/blob/4.4.1/conda/plan.py#L515

I guess in conda 4.4 that took on more/different importance.

That parameter currently isn't being passed by conda-build:
https://github.com/conda/conda-build/blob/3.2.0/conda_build/environ.py#L691

So conda is falling back to whatever is configured for `context.channels`.

I think we're going to have to talk through this to figure out how to address it.
Does this mean there is an unintentional change to the exported behavior conda build uses? I think we should prioritize restoring that behavior.

But 4.3.x has the `channel_priority_map` input as well, so I don't understand why it would behave differently in 4.4.


In 4.3, we set channel priority on each individual record every time we build the index.  In 4.4, we hand channel priority over to Resolve, and let Resolve handle all the dynamic parts of priority.

Stuffing that level of mutability inside of an index record was always problematic.  We have the same issue of `add_pip_as_python_dependency`.  

Conda-build probably wasn't using that parameter on `install_actions()` because it wasn't important before now, for the flows that conda-build uses (i.e. calling conda's get_index, and then handing that index back to the solver).

I can probably hack something together in conda to make this work again, but I'm pretty sure there will be a performance hit for all the translation.

Maybe it's worthwhile for us to do a code review of the much cleaner APIs that conda 4.4 has for the Solver, and the three individual information sources (i.e. package cache, prefix, and repodata).  The Solver API is already locked down in `conda/api.py`, and we can easily do the same thing for the three lower-level APIs too.  Then start thinking about how conda-build can make use of them.
OK, so I get that this is an unintentional change, but I think we have to go with the perfomance hit here and revert. Perhaps there's a way to mitigate the performance hit.
An alternative is if we can come up with an easy way on the conda-build side to do the right thing, but it would have to work with conda 4.3 and 4.4...
Can I pass a reasonable channel map somehow?

Resolving patch:
diff --git a/conda/core/index.py b/conda/core/index.py
--- a/conda/core/index.py
+++ b/conda/core/index.py
@@ -44,6 +44,8 @@ def check_whitelist(channel_urls):
                                           % (bad_channel.location, bad_channel.canonical_name))
 
 
+LAST_CHANNEL_URLS = []
+
 @time_recorder("get_index")
 def get_index(channel_urls=(), prepend=True, platform=None,
               use_local=False, use_cache=False, unknown=None, prefix=None):
@@ -58,6 +60,8 @@ def get_index(channel_urls=(), prepend=True, platform=None,
         unknown = True
 
     channel_urls = calculate_channel_urls(channel_urls, prepend, platform, use_local)
+    del LAST_CHANNEL_URLS[:]
+    LAST_CHANNEL_URLS.extend(channel_urls)
 
     check_whitelist(channel_urls)
 
diff --git a/conda/plan.py b/conda/plan.py
--- a/conda/plan.py
+++ b/conda/plan.py
@@ -18,7 +18,7 @@
 from .base.context import context
 from .common.compat import itervalues, text_type
 from .common.io import time_recorder
-from .core.index import _supplement_index_with_prefix
+from .core.index import _supplement_index_with_prefix, LAST_CHANNEL_URLS
 from .core.link import PrefixSetup, UnlinkLinkTransaction
 from .core.linked_data import is_linked, linked_data
 from .core.solve import get_pinned_specs
@@ -26,7 +26,7 @@
 from .history import History
 from .instructions import (CHECK_EXTRACT, CHECK_FETCH, EXTRACT, FETCH, LINK, PREFIX,
                            RM_EXTRACTED, RM_FETCHED, SYMLINK_CONDA, UNLINK)
-from .models.channel import Channel
+from .models.channel import Channel, prioritize_channels
 from .models.dist import Dist
 from .models.enums import LinkType
 from .models.version import normalized_version
@@ -527,7 +527,13 @@ def install_actions(prefix, index, specs, force=False, only_names=None, always_c
         channels = IndexedSet(Channel(cn) for cn in channel_names)
         subdirs = IndexedSet(basename(url) for url in channel_priority_map)
     else:
-        channels = subdirs = None
+        if LAST_CHANNEL_URLS:
+            channel_priority_map = prioritize_channels(LAST_CHANNEL_URLS)
+            channel_names = IndexedSet(Channel(url).canonical_name for url in channel_priority_map)
+            channels = IndexedSet(Channel(cn) for cn in channel_names)
+            subdirs = IndexedSet(basename(url) for url in channel_priority_map)
+        else:
+            channels = subdirs = None
 
     specs = tuple(MatchSpec(spec) for spec in specs)
 
diff --git a/conda/resolve.py b/conda/resolve.py
--- a/conda/resolve.py
+++ b/conda/resolve.py
@@ -390,7 +390,7 @@ def ms_depends(self, dist):
     def version_key(self, dist, vtype=None):
         rec = self.index[dist]
         channel = rec.channel
-        channel_priority = self._channel_priorities_map.get(channel.canonical_name, 1)
+        channel_priority = self._channel_priorities_map.get(channel.name, 1)  # TODO: ask @mcg1969 why the default value is 1 here  # NOQA
         valid = 1 if channel_priority < MAX_CHANNEL_PRIORITY else 0
         version_comparator = VersionOrder(rec.get('version', ''))
         build_number = rec.get('build_number', 0)
@@ -408,7 +408,7 @@ def _make_channel_priorities(channels):
             (Channel(cc) for cc in c._channels) if isinstance(c, MultiChannel) else (c,)
             for c in (Channel(c) for c in channels)
         )):
-            channel_name = chn.canonical_name
+            channel_name = chn.name
             if channel_name in priorities_map:
                 continue
             priorities_map[channel_name] = min(priority_counter, MAX_CHANNEL_PRIORITY - 1)


Test patch: