Repository: conda/conda

Issue:
Conda does not respect exact matchspecs
Really strange here, but I've followed this as far as I can in conda-build, and I think it's in conda.

I have these specs:

```
ipdb> sub_build_ms_deps
[MatchSpec('openssl 1.0.2k 1'), MatchSpec('zlib 1.2.8 3'), MatchSpec('bzip2 1.0.6 3'), 
MatchSpec('ncurses 5.9 10'), MatchSpec('curl 7.52.1 0'), 
MatchSpec('llvm 4.0.0 h95a1600_0'), MatchSpec('cmake 3.6.3 0'), 
MatchSpec('xz 5.2.2 1'), MatchSpec('expat 2.1.0 0')]
```

These get fed into conda's install_actions function here: https://github.com/conda/conda-build/blob/master/conda_build/environ.py#L655

```
ipdb> n
> /home/msarahan/conda-build/conda_build/build.py(1042)build()
   1041                     index, index_timestamp = get_build_index(m.config, m.config.build_subdir)
-> 1042                     build_actions = environ.get_install_actions(m.config.build_prefix, index,
   1043                                                                 sub_build_ms_deps, m.config,
```

Now I'm not 100% certain that the package exists in repodata yet.  I know that it does on disk, but not sure about in-memory.  It should, but I'm not certain.

My confusion is why with that matchspec for llvm in particular, build string h95a1600, should I *ever* be given a non-matching build string?

```
ipdb> build_actions
defaultdict(<type 'list'>, {u'op_order': ('CHECK_FETCH', 'RM_FETCHED', 'FETCH', 'CHECK_EXTRACT', 'RM_EXTRACTED', 'EXTRACT', 'UNLINK', 'LINK', 'SYMLINK_CONDA'), 'SYMLINK_CONDA': ['/home/msarahan/miniconda2'], 'PREFIX': '/home/msarahan/miniconda2/conda-bld/llvm_1494542025512/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_pla', 
'LINK': [
Dist(_Dist__initd=True, channel=u'defaults', dist_name=u'bzip2-1.0.6-3', name=u'bzip2', version=u'1.0.6', build_string=u'3', build_number=3, with_features_depends=None, base_url=None, platform=None), 
Dist(_Dist__initd=True, channel=u'defaults', dist_name=u'expat-2.1.0-0', name=u'expat', version=u'2.1.0', build_string=u'0', build_number=0, with_features_depends=None, base_url=None, platform=None), 
Dist(_Dist__initd=True, channel=u'local', dist_name=u'llvm-4.0.0-heefb760_0', name=u'llvm', version=u'4.0.0', build_string=u'heefb760_0', build_number=0, with_features_depends=None, base_url=None, platform=None), 
Dist(_Dist__initd=True, channel=u'defaults', dist_name=u'ncurses-5.9-10', name=u'ncurses', version=u'5.9', build_string=u'10', build_number=10, with_features_depends=None, base_url=None, platform=None), 
Dist(_Dist__initd=True, channel=u'defaults', dist_name=u'openssl-1.0.2k-1', name=u'openssl', version=u'1.0.2k', build_string=u'1', build_number=1, with_features_depends=None, base_url=None, platform=None), 
Dist(_Dist__initd=True, channel=u'defaults', dist_name=u'xz-5.2.2-1', name=u'xz', version=u'5.2.2', build_string=u'1', build_number=1, with_features_depends=None, base_url=None, platform=None), 
Dist(_Dist__initd=True, channel=u'defaults', dist_name=u'zlib-1.2.8-3', name=u'zlib', version=u'1.2.8', build_string=u'3', build_number=3, with_features_depends=None, base_url=None, platform=None), 
Dist(_Dist__initd=True, channel=u'defaults', dist_name=u'curl-7.52.1-0', name=u'curl', version=u'7.52.1', build_string=u'0', build_number=0, with_features_depends=None, base_url=None, platform=None), 
Dist(_Dist__initd=True, channel=u'defaults', dist_name=u'cmake-3.6.3-0', name=u'cmake', version=u'3.6.3', build_string=u'0', build_number=0, with_features_depends=None, base_url=None, platform=None)]})
```

Note the relevant bit in the install actions:  ```dist_name=u'llvm-4.0.0-heefb760_0', ```

This is with conda 4.3.17.


Discussion:
PS: to make things even more confusing, heefb760 is an older build, done yesterday, while the h95a1600 build is from today - so it isn't the timestamp prioritization messing up.
Just wrote a simple test that I expected to fail:

```python
def test_build_string():
    # regression test for #5298
    spec = MatchSpec('llvm 4.0.0 h95a1600_0')

    dist1 = Dist("local::llvm-4.0.0-h95a1600_0")
    assert spec.match(dist1)

    dist2 = Dist("local::llvm-4.0.0-heefb760_0")
    assert not spec.match(dist2)
```

But it passes.  So still looking...
I guess I need to dig into what the solver is doing.  @msarahan would it be possible for you to upload those two llvm packages to the `conda-test` channel so that I can try to reproduce the behavior?
https://anaconda.org/msarahan/llvm/files

I have the whole miniconda env preserved also if you need it.  Is that install_actions possibly doing anything differently from MatchSpec.match?  Seems like it's running the solver, rather than just finding something in an index.
Yeah `install_actions` is basically conda-builds interface to the solver right now.  And I do think what's going on here is something in resolve.py that I need to track down.
@msarahan were you going to upload those two llvm packages to the `conda-test` channel?  That would be helpful.
@msarahan Just for osx-64 is fine.
No, please use them from my channel, as I linked above.  These packages are for Linux only.  Please use a VM or docker image as necessary.

If you want to download them from my channel and re-upload them to the conda-test channel for the sake of future testing, that's fine.
Oh, I see.  Missed that.  Sorry.
In theory, I should be able to reproduce this behavior now with the command

    conda create --dry-run -n testest llvm=4.0.0=h95a1600_0 -c msarahan

and in the conda code changing the `install_actions_list()` function in `conda/plan.py` to

```python
def install_actions_list(prefix, index, specs, force=False, only_names=None, always_copy=False,
                         pinned=True, minimal_hint=False, update_deps=True, prune=False,
                         channel_priority_map=None, is_update=False):
    result = [install_actions(prefix, index, specs, force, only_names, always_copy,
                            pinned, minimal_hint, update_deps, prune,
                            channel_priority_map, is_update)]
    print(result)
    return result
```

to be extra sure that conda and conda-build are using exactly the same code paths.

I'm so far unable to reproduce the behavior.

```
[vagrant@localhost vagrant]$ python -m conda create --dry-run -n testest -c msarahan openssl=1.0.2k=1 zlib=1.2.8=3 bzip2=1.0.6=3 ncurses=5.9=10 curl=7.52.1=0 cmake=3.6.3=0 xz=5.2.2=1 expat=2.1.0=0 llvm=4.0.0=h95a1600_0
Fetching package metadata ...........
Solving package specifications: .
[defaultdict(<class 'list'>, {'LINK': [Dist(_Dist__initd=True, channel='defaults', dist_name='bzip2-1.0.6-3', name='bzip2', version='1.0.6', build_string='3', build_number=3, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='defaults', dist_name='expat-2.1.0-0', name='expat', version='2.1.0', build_string='0', build_number=0, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='msarahan', dist_name='libgcc_linux-cos6-x86_64-6.3.0-h1011ec8_0', name='libgcc_linux-cos6-x86_64', version='6.3.0', build_string='h1011ec8_0', build_number=0, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='msarahan', dist_name='libstdcxx_linux-cos6-x86_64-6.3.0-h1011ec8_0', name='libstdcxx_linux-cos6-x86_64', version='6.3.0', build_string='h1011ec8_0', build_number=0, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='defaults', dist_name='ncurses-5.9-10', name='ncurses', version='5.9', build_string='10', build_number=10, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='defaults', dist_name='openssl-1.0.2k-1', name='openssl', version='1.0.2k', build_string='1', build_number=1, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='defaults', dist_name='xz-5.2.2-1', name='xz', version='5.2.2', build_string='1', build_number=1, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='msarahan', dist_name='zlib-1.2.8-3', name='zlib', version='1.2.8', build_string='3', build_number=3, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='defaults', dist_name='curl-7.52.1-0', name='curl', version='7.52.1', build_string='0', build_number=0, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='msarahan', dist_name='llvm-4.0.0-h95a1600_0', name='llvm', version='4.0.0', build_string='h95a1600_0', build_number=0, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='defaults', dist_name='cmake-3.6.3-0', name='cmake', version='3.6.3', build_string='0', build_number=0, with_features_depends=None, base_url=None, platform=None)], 'op_order': ('CHECK_FETCH', 'RM_FETCHED', 'FETCH', 'CHECK_EXTRACT', 'RM_EXTRACTED', 'EXTRACT', 'UNLINK', 'LINK', 'SYMLINK_CONDA'), 'SYMLINK_CONDA': ['/usr/local'], 'PREFIX': '/home/vagrant/.conda/envs/testest'})]

Package plan for installation in environment /home/vagrant/.conda/envs/testest:

The following NEW packages will be INSTALLED:

    bzip2:                       1.0.6-3
    cmake:                       3.6.3-0
    curl:                        7.52.1-0
    expat:                       2.1.0-0
    libgcc_linux-cos6-x86_64:    6.3.0-h1011ec8_0 msarahan
    libstdcxx_linux-cos6-x86_64: 6.3.0-h1011ec8_0 msarahan
    llvm:                        4.0.0-h95a1600_0 msarahan
    ncurses:                     5.9-10
    openssl:                     1.0.2k-1
    xz:                          5.2.2-1
    zlib:                        1.2.8-3          msarahan

[vagrant@localhost vagrant]$ python -m conda create --dry-run -n testest -c msarahan openssl=1.0.2k=1 zlib=1.2.8=3 bzip2=1.0.6=3 ncurses=5.9=10 curl=7.52.1=0 cmake=3.6.3=0 xz=5.2.2=1 expat=2.1.0=0 llvm=4.0.0=heefb760_0
Fetching package metadata ...........
Solving package specifications: .
[defaultdict(<class 'list'>, {'PREFIX': '/home/vagrant/.conda/envs/testest', 'SYMLINK_CONDA': ['/usr/local'], 'op_order': ('CHECK_FETCH', 'RM_FETCHED', 'FETCH', 'CHECK_EXTRACT', 'RM_EXTRACTED', 'EXTRACT', 'UNLINK', 'LINK', 'SYMLINK_CONDA'), 'LINK': [Dist(_Dist__initd=True, channel='defaults', dist_name='bzip2-1.0.6-3', name='bzip2', version='1.0.6', build_string='3', build_number=3, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='defaults', dist_name='expat-2.1.0-0', name='expat', version='2.1.0', build_string='0', build_number=0, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='msarahan', dist_name='llvm-4.0.0-heefb760_0', name='llvm', version='4.0.0', build_string='heefb760_0', build_number=0, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='defaults', dist_name='ncurses-5.9-10', name='ncurses', version='5.9', build_string='10', build_number=10, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='defaults', dist_name='openssl-1.0.2k-1', name='openssl', version='1.0.2k', build_string='1', build_number=1, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='defaults', dist_name='xz-5.2.2-1', name='xz', version='5.2.2', build_string='1', build_number=1, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='msarahan', dist_name='zlib-1.2.8-3', name='zlib', version='1.2.8', build_string='3', build_number=3, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='defaults', dist_name='curl-7.52.1-0', name='curl', version='7.52.1', build_string='0', build_number=0, with_features_depends=None, base_url=None, platform=None), Dist(_Dist__initd=True, channel='defaults', dist_name='cmake-3.6.3-0', name='cmake', version='3.6.3', build_string='0', build_number=0, with_features_depends=None, base_url=None, platform=None)]})]

Package plan for installation in environment /home/vagrant/.conda/envs/testest:

The following NEW packages will be INSTALLED:

    bzip2:   1.0.6-3
    cmake:   3.6.3-0
    curl:    7.52.1-0
    expat:   2.1.0-0
    llvm:    4.0.0-heefb760_0 msarahan
    ncurses: 5.9-10
    openssl: 1.0.2k-1
    xz:      5.2.2-1
    zlib:    1.2.8-3          msarahan

```

Resolving patch:
diff --git a/conda/resolve.py b/conda/resolve.py
--- a/conda/resolve.py
+++ b/conda/resolve.py
@@ -531,7 +531,7 @@ def version_key(self, dist, vtype=None):
         valid = 1 if cpri < MAX_CHANNEL_PRIORITY else 0
         ver = normalized_version(rec.get('version', ''))
         bld = rec.get('build_number', 0)
-        bs = rec.get('build_string')
+        bs = rec.get('build')
         ts = rec.get('timestamp', 0)
         return ((valid, -cpri, ver, bld, bs, ts) if context.channel_priority else
                 (valid, ver, -cpri, bld, bs, ts))


Test patch: