Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/4.5.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
kalefranz committed Jul 11, 2018
2 parents 7c1b96a + 3decbfd commit 2cd76c7
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 29 deletions.
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,31 @@
* @mbargull


## 4.5.8 (2018-07-10)

### Bug Fixes

* fix #7524 should_bypass_proxies for requests 2.13.0 and earlier (#7525)

### Contributors
@kalefranz


## 4.5.7 (2018-07-09)

### Improvements
* resolve #7423 add upgrade error for unsupported repodata_version (#7415)
* raise CondaUpgradeError for conda version downgrades on environments (#7517)

### Bug Fixes
* fix #7505 temp directory for UnlinkLinkTransaction should be in target prefix (#7516)
* fix #7506 requests monkeypatch fallback for old requests versions (#7515)

### Contributors
@kalefranz
@nehaljwani


## 4.5.6 (2018-07-06)

### Bug Fixes
Expand Down
1 change: 1 addition & 0 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ conda_build_test: &conda_build_test
conda create -n blarg -yq --download-only python=3.4
conda create -n blarg -yq --download-only python=3.5
conda create -n blarg -yq --download-only python=3.6
conda create -n blarg -yq --download-only python=3.7
conda create -n blarg -yq --download-only python setuptools cython certifi
conda create -n blarg -yq --download-only libpng=1.6.17
Expand Down
25 changes: 23 additions & 2 deletions conda/core/subdir_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
from ..common.io import ThreadLimitedThreadPoolExecutor, as_completed
from ..common.url import join_url, maybe_unquote
from ..core.package_cache_data import PackageCacheData
from ..exceptions import (CondaDependencyError, CondaHTTPError, UnavailableInvalidChannel,
NotWritableError)
from ..exceptions import (CondaDependencyError, CondaHTTPError, CondaUpgradeError,
NotWritableError, UnavailableInvalidChannel)
from ..gateways.connection import (ConnectionError, HTTPError, InsecureRequestWarning,
InvalidSchema, SSLError)
from ..gateways.connection.session import CondaSession
Expand All @@ -53,6 +53,7 @@
stderrlog = getLogger('conda.stderrlog')

REPODATA_PICKLE_VERSION = 25
MAX_REPODATA_VERSION = 1
REPODATA_HEADER_RE = b'"(_etag|_mod|_cache_control)":[ ]?"(.*?[^\\\\])"[,\}\s]'


Expand Down Expand Up @@ -147,6 +148,16 @@ def cache_path_pickle(self):

def load(self):
_internal_state = self._load()
if _internal_state["repodata_version"] > MAX_REPODATA_VERSION:
raise CondaUpgradeError(dals("""
The current version of conda is too old to read repodata from
%s
(This version only supports repodata_version 1.)
Please update conda to use this channel.
""") % self.url_w_subdir)

self._internal_state = _internal_state
self._package_records = _internal_state['_package_records']
self._names_index = _internal_state['_names_index']
Expand Down Expand Up @@ -325,7 +336,17 @@ def _process_raw_repodata_str(self, raw_repodata_str):
'_add_pip': add_pip,
'_pickle_version': REPODATA_PICKLE_VERSION,
'_schannel': schannel,
'repodata_version': json_obj.get('repodata_version', 0),
}
if _internal_state["repodata_version"] > MAX_REPODATA_VERSION:
raise CondaUpgradeError(dals("""
The current version of conda is too old to read repodata from
%s
(This version only supports repodata_version 1.)
Please update conda to use this channel.
""") % self.url_w_subdir)

meta_in_common = { # just need to make this once, then apply with .update()
'arch': json_obj.get('info', {}).get('arch'),
Expand Down
2 changes: 1 addition & 1 deletion conda/gateways/connection/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from __future__ import absolute_import, division, print_function, unicode_literals
from functools import partial

def should_bypass_proxies_patched(should_bypass_proxies_func, url, no_proxy):
def should_bypass_proxies_patched(should_bypass_proxies_func, url, no_proxy=None):
# Monkey patch requests, per https://github.com/requests/requests/pull/4723
if url.startswith("file://"):
return True
Expand Down
8 changes: 5 additions & 3 deletions conda/gateways/disk/read.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,14 @@ def _paths():
return None
else:
with open(path, 'r') as f:
package_metadata = PackageMetadata(**json.loads(f.read()))
if package_metadata.package_metadata_version != 1:
data = json.loads(f.read())
if data.get('package_metadata_version') != 1:
raise CondaUpgradeError(dals("""
The current version of conda is too old to install this package. (This version
only supports link.json schema version 1.) Please update conda to install
this package."""))
this package.
"""))
package_metadata = PackageMetadata(**data)
return package_metadata


Expand Down
60 changes: 49 additions & 11 deletions conda/history.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,34 @@
from __future__ import absolute_import, division, print_function, unicode_literals

from ast import literal_eval
import errno
from errno import EACCES, EPERM
import logging
from operator import itemgetter
import os
from os.path import isdir, isfile, join
import re
import sys
import warnings

from textwrap import dedent
import time
import warnings

from . import __version__ as CONDA_VERSION
from ._vendor.auxlib.ish import dals
from .base.constants import DEFAULTS_CHANNEL_NAME
from .base.context import context
from .common.compat import ensure_text_type, iteritems, open, text_type
from .common.path import paths_equal
from .core.prefix_data import PrefixData
from .exceptions import CondaFileIOError, CondaHistoryError
from .exceptions import CondaHistoryError, CondaUpgradeError, NotWritableError
from .gateways.disk.update import touch
from .models.dist import dist_str_to_quad
from .models.version import version_relation_re
from .models.version import VersionOrder, version_relation_re
from .resolve import MatchSpec

try:
from cytoolz.itertoolz import groupby
from cytoolz.itertoolz import groupby, take
except ImportError: # pragma: no cover
from ._vendor.toolz.itertoolz import groupby # NOQA
from ._vendor.toolz.itertoolz import groupby, take # NOQA


log = logging.getLogger(__name__)
Expand All @@ -40,6 +44,7 @@ class CondaHistoryWarning(Warning):
def write_head(fo):
fo.write("==> %s <==\n" % time.strftime('%Y-%m-%d %H:%M:%S'))
fo.write("# cmd: %s\n" % (' '.join(ensure_text_type(s) for s in sys.argv)))
fo.write("# conda version: %s\n" % '.'.join(take(3, CONDA_VERSION.split('.'))))


def is_diff(content):
Expand Down Expand Up @@ -78,6 +83,7 @@ class History(object):

com_pat = re.compile(r'#\s*cmd:\s*(.+)')
spec_pat = re.compile(r'#\s*(\w+)\s*specs:\s*(.+)?')
conda_v_pat = re.compile(r'#\s*conda version:\s*(.+)')

def __init__(self, prefix):
self.prefix = prefix
Expand Down Expand Up @@ -111,11 +117,11 @@ def update(self):
pd = PrefixData(self.prefix)
curr = set(prefix_rec.dist_str() for prefix_rec in pd.iter_records())
self.write_changes(last, curr)
except IOError as e:
if e.errno == errno.EACCES:
log.debug("Can't write the history file")
except EnvironmentError as e:
if e.errno in (EACCES, EPERM):
raise NotWritableError(self.path, e.errno)
else:
raise CondaFileIOError(self.path, "Can't write the history file %s" % e)
raise

def parse(self):
"""
Expand Down Expand Up @@ -181,6 +187,10 @@ def _parse_comment_line(cls, line):
argv[0] = 'conda'
item['cmd'] = argv

m = cls.conda_v_pat.match(line)
if m:
item['conda_version'] = m.group(1)

m = cls.spec_pat.match(line)
if m:
action, specs_string = m.groups()
Expand Down Expand Up @@ -224,6 +234,34 @@ def get_user_requests(self):
item['unlink_dists'] = dists.get('-', ())
item['link_dists'] = dists.get('+', ())

conda_versions_from_history = tuple(x['conda_version'] for x in res
if 'conda_version' in x)
if conda_versions_from_history:
minimum_conda_version = sorted(conda_versions_from_history, key=VersionOrder)[-1]
minimum_major_minor = '.'.join(take(2, minimum_conda_version.split('.')))
current_major_minor = '.'.join(take(2, CONDA_VERSION.split('.')))
if VersionOrder(current_major_minor) < VersionOrder(minimum_major_minor):
message = dals("""
This environment has previously been operated on by a conda version that's newer
than the conda currently being used. A newer version of conda is required.
target environment location: %(target_prefix)s
current conda version: %(conda_version)s
minimum conda version: %(minimum_version)s
""") % {
"target_prefix": self.prefix,
"conda_version": CONDA_VERSION,
"minimum_version": minimum_major_minor,
}
if not paths_equal(self.prefix, context.root_prefix):
message += dedent("""
Update conda and try again.
$ conda install -p "%(base_prefix)s" "conda>=%(minimum_version)s"
""") % {
"base_prefix": context.root_prefix,
"minimum_version": minimum_major_minor,
}
raise CondaUpgradeError(message)

return res

def get_requested_specs_map(self):
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ exclude = build/*,.tox/*,env/*,tests/*,ve/*,*/_vendor/*,conda/compat.py,conda/co
[flake8]
max-line-length = 99
ignore = E126,E133,E226,E241,E242,E302,E704,E731,E722,W503
exclude = build/*,.tox/*,env/*,tests/*,ve/*,*/_vendor/*,conda/compat.py,conda/common/compat.py,conda_env/compat.py,devenv/*
exclude = build/*,.tox/*,devenv/*,env/*,tests/*,ve/*,*/_vendor/*,conda/compat.py,conda/common/compat.py,conda_env/compat.py


[coverage:report]
Expand Down
44 changes: 33 additions & 11 deletions tests/test_history.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
from os.path import dirname
from os.path import dirname, isfile, join
from pprint import pprint
from shutil import copy2
import unittest

import pytest

from conda.exceptions import CondaUpgradeError
from conda.gateways.disk import mkdir_p
from .decorators import skip_if_no_mock
from .helpers import mock
from .helpers import mock, tempdir
from .test_create import make_temp_prefix

from conda.history import History
Expand Down Expand Up @@ -82,15 +87,10 @@ def test_last(self):
'link_dists': ['+pyflakes-1.0.0-py27_0'],
})

def test_conda_comment_version_parsin(self):
test_cases = [
"# conda version: 4.5.1",
"# conda version: 4.5.1rc1",
"# conda version: 4.5.1dev0",
]
for line in test_cases:
item = History._parse_comment_line(line)
assert not item
def test_conda_comment_version_parsing(self):
assert History._parse_comment_line("# conda version: 4.5.1") == {"conda_version": "4.5.1"}
assert History._parse_comment_line("# conda version: 4.5.1rc1") == {"conda_version": "4.5.1rc1"}
assert History._parse_comment_line("# conda version: 4.5.1dev0") == {"conda_version": "4.5.1dev0"}

def test_specs_line_parsing_44(self):
# New format (>=4.4)
Expand Down Expand Up @@ -183,3 +183,25 @@ def test_specs_line_parsing_43(self):
'pandas', '_license >=1.0.0,<2.0',
],
}


def test_minimum_conda_version_error():
with tempdir() as prefix:
assert not isfile(join(prefix, 'conda-meta', 'history'))
mkdir_p(join(prefix, 'conda-meta'))
copy2(join(dirname(__file__), 'conda-meta', 'history'),
join(prefix, 'conda-meta', 'history'))

with open(join(prefix, 'conda-meta', 'history'), 'a') as fh:
fh.write("==> 2018-07-09 11:18:09 <==\n")
fh.write("# cmd: blarg\n")
fh.write("# conda version: 42.42.4242\n")

h = History(prefix)

with pytest.raises(CondaUpgradeError) as exc:
h.get_user_requests()
exception_string = repr(exc.value)
print(exception_string)
assert "minimum conda version: 42.42" in exception_string
assert "$ conda install -p" in exception_string

0 comments on commit 2cd76c7

Please sign in to comment.