We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
python 2 can't read unicode in environments.txt
on a conda install operation, during the transaction

```
Traceback (most recent call last):
  File "/Users/kfranz/continuum/conda/conda/core/link.py", line 535, in _execute_actions
    action.execute()
  File "/Users/kfranz/continuum/conda/conda/core/path_actions.py", line 876, in execute
    register_env(self.target_prefix)
  File "/Users/kfranz/continuum/conda/conda/core/envs_manager.py", line 28, in register_env
    if location in yield_lines(USER_ENVIRONMENTS_TXT_FILE):
  File "/Users/kfranz/continuum/conda/conda/gateways/disk/read.py", line 49, in yield_lines
    if not line or line.startswith('#'):
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 54: ordinal not in range(128)
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `conda/gateways/disk/read.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 from __future__ import absolute_import, division, print_function, unicode_literals
3 
4 from base64 import b64encode
5 from collections import namedtuple
6 from errno import ENOENT
7 from functools import partial
8 from glob import glob
9 import hashlib
10 from itertools import chain
11 import json
12 from logging import getLogger
13 from os import listdir
14 from os.path import isdir, isfile, join
15 import shlex
16 import tarfile
17 
18 from .link import islink, lexists
19 from ..._vendor.auxlib.collection import first
20 from ..._vendor.auxlib.ish import dals
21 from ...base.constants import PREFIX_PLACEHOLDER
22 from ...common.compat import ensure_text_type
23 from ...exceptions import CondaUpgradeError, CondaVerificationError, PathNotFoundError
24 from ...models.channel import Channel
25 from ...models.enums import FileMode, PathType
26 from ...models.index_record import IndexJsonRecord, IndexRecord, PathData, PathDataV1, PathsData
27 from ...models.package_info import PackageInfo, PackageMetadata
28 
29 log = getLogger(__name__)
30 
31 listdir = listdir
32 lexists, isdir, isfile = lexists, isdir, isfile
33 
34 
35 def yield_lines(path):
36     """Generator function for lines in file.  Empty generator if path does not exist.
37 
38     Args:
39         path (str): path to file
40 
41     Returns:
42         iterator: each line in file, not starting with '#'
43 
44     """
45     try:
46         with open(path) as fh:
47             for line in fh:
48                 line = line.strip()
49                 if not line or line.startswith('#'):
50                     continue
51                 yield line
52     except (IOError, OSError) as e:
53         if e.errno == ENOENT:
54             pass
55         else:
56             raise
57 
58 
59 def _digest_path(algo, path):
60     if not isfile(path):
61         raise PathNotFoundError(path)
62 
63     hasher = hashlib.new(algo)
64     with open(path, "rb") as fh:
65         for chunk in iter(partial(fh.read, 8192), b''):
66             hasher.update(chunk)
67     return hasher.hexdigest()
68 
69 
70 def compute_md5sum(file_full_path):
71     return _digest_path('md5', file_full_path)
72 
73 
74 def compute_sha256sum(file_full_path):
75     return _digest_path('sha256', file_full_path)
76 
77 
78 def find_first_existing(*globs):
79     for g in globs:
80         for path in glob(g):
81             if lexists(path):
82                 return path
83     return None
84 
85 
86 # ####################################################
87 # functions supporting read_package_info()
88 # ####################################################
89 
90 def read_package_info(record, package_cache_record):
91     epd = package_cache_record.extracted_package_dir
92     index_json_record = read_index_json(epd)
93     icondata = read_icondata(epd)
94     package_metadata = read_package_metadata(epd)
95     paths_data = read_paths_json(epd)
96 
97     return PackageInfo(
98         extracted_package_dir=epd,
99         channel=Channel(record.schannel or record.channel),
100         repodata_record=record,
101         url=package_cache_record.url,
102 
103         index_json_record=index_json_record,
104         icondata=icondata,
105         package_metadata=package_metadata,
106         paths_data=paths_data,
107     )
108 
109 
110 def read_index_json(extracted_package_directory):
111     with open(join(extracted_package_directory, 'info', 'index.json')) as fi:
112         record = IndexJsonRecord(**json.load(fi))
113     return record
114 
115 
116 def read_index_json_from_tarball(package_tarball_full_path):
117     with tarfile.open(package_tarball_full_path) as tf:
118         contents = tf.extractfile('info/index.json').read()
119         return IndexJsonRecord(**json.loads(ensure_text_type(contents)))
120 
121 
122 def read_repodata_json(extracted_package_directory):
123     with open(join(extracted_package_directory, 'info', 'repodata_record.json')) as fi:
124         record = IndexRecord(**json.load(fi))
125     return record
126 
127 
128 def read_icondata(extracted_package_directory):
129     icon_file_path = join(extracted_package_directory, 'info', 'icon.png')
130     if isfile(icon_file_path):
131         with open(icon_file_path, 'rb') as f:
132             data = f.read()
133         return b64encode(data).decode('utf-8')
134     else:
135         return None
136 
137 
138 def read_package_metadata(extracted_package_directory):
139     def _paths():
140         yield join(extracted_package_directory, 'info', 'link.json')
141         yield join(extracted_package_directory, 'info', 'package_metadata.json')
142 
143     path = first(_paths(), key=isfile)
144     if not path:
145         return None
146     else:
147         with open(path, 'r') as f:
148             package_metadata = PackageMetadata(**json.loads(f.read()))
149             if package_metadata.package_metadata_version != 1:
150                 raise CondaUpgradeError(dals("""
151                 The current version of conda is too old to install this package. (This version
152                 only supports link.json schema version 1.)  Please update conda to install
153                 this package."""))
154         return package_metadata
155 
156 
157 def read_paths_json(extracted_package_directory):
158     info_dir = join(extracted_package_directory, 'info')
159     paths_json_path = join(info_dir, 'paths.json')
160     if isfile(paths_json_path):
161         with open(paths_json_path) as paths_json:
162             data = json.load(paths_json)
163         if data.get('paths_version') != 1:
164             raise CondaUpgradeError(dals("""
165             The current version of conda is too old to install this package. (This version
166             only supports paths.json schema version 1.)  Please update conda to install
167             this package."""))
168         paths_data = PathsData(
169             paths_version=1,
170             paths=(PathDataV1(**f) for f in data['paths']),
171         )
172     else:
173         has_prefix_files = read_has_prefix(join(info_dir, 'has_prefix'))
174         no_link = read_no_link(info_dir)
175 
176         def read_files_file():
177             files_path = join(info_dir, 'files')
178             for f in (ln for ln in (line.strip() for line in yield_lines(files_path)) if ln):
179                 path_info = {"_path": f}
180                 if f in has_prefix_files.keys():
181                     path_info["prefix_placeholder"] = has_prefix_files[f][0]
182                     path_info["file_mode"] = has_prefix_files[f][1]
183                 if f in no_link:
184                     path_info["no_link"] = True
185                 if islink(join(extracted_package_directory, f)):
186                     path_info["path_type"] = PathType.softlink
187                 else:
188                     path_info["path_type"] = PathType.hardlink
189                 yield PathData(**path_info)
190 
191         paths = tuple(read_files_file())
192         paths_data = PathsData(
193             paths_version=0,
194             paths=paths,
195         )
196     return paths_data
197 
198 
199 def read_has_prefix(path):
200     """
201     reads `has_prefix` file and return dict mapping filepaths to tuples(placeholder, FileMode)
202 
203     A line in `has_prefix` contains one of
204       * filepath
205       * placeholder mode filepath
206 
207     mode values are one of
208       * text
209       * binary
210     """
211     ParseResult = namedtuple('ParseResult', ('placeholder', 'filemode', 'filepath'))
212 
213     def parse_line(line):
214         # placeholder, filemode, filepath
215         parts = tuple(x.strip('"\'') for x in shlex.split(line, posix=False))
216         if len(parts) == 1:
217             return ParseResult(PREFIX_PLACEHOLDER, FileMode.text, parts[0])
218         elif len(parts) == 3:
219             return ParseResult(parts[0], FileMode(parts[1]), parts[2])
220         else:
221             raise CondaVerificationError("Invalid has_prefix file at path: %s" % path)
222 
223     parsed_lines = (parse_line(line) for line in yield_lines(path))
224     return {pr.filepath: (pr.placeholder, pr.filemode) for pr in parsed_lines}
225 
226 
227 def read_no_link(info_dir):
228     return set(chain(yield_lines(join(info_dir, 'no_link')),
229                      yield_lines(join(info_dir, 'no_softlink'))))
230 
231 
232 def read_soft_links(extracted_package_directory, files):
233     return tuple(f for f in files if islink(join(extracted_package_directory, f)))
234
```

Path: `conda/core/envs_manager.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 from __future__ import absolute_import, division, print_function, unicode_literals
3 
4 from logging import getLogger
5 from os import listdir
6 from os.path import dirname, isdir, isfile, join, normpath, split as path_split
7 
8 from ..base.constants import ROOT_ENV_NAME
9 from ..base.context import context
10 from ..common.compat import on_win
11 from ..common.path import expand, paths_equal
12 from ..gateways.disk.read import yield_lines
13 from ..gateways.disk.test import is_conda_environment
14 
15 log = getLogger(__name__)
16 
17 
18 USER_ENVIRONMENTS_TXT_FILE = expand(join('~', '.conda', 'environments.txt'))
19 
20 
21 def register_env(location):
22     location = normpath(location)
23 
24     if "placehold_pl" in location:
25         # Don't record envs created by conda-build.
26         return
27 
28     if location in yield_lines(USER_ENVIRONMENTS_TXT_FILE):
29         # Nothing to do. Location is already recorded in a known environments.txt file.
30         return
31 
32     with open(USER_ENVIRONMENTS_TXT_FILE, 'a') as fh:
33         fh.write(location)
34         fh.write('\n')
35 
36 
37 def unregister_env(location):
38     if isdir(location):
39         meta_dir = join(location, 'conda-meta')
40         if isdir(meta_dir):
41             meta_dir_contents = listdir(meta_dir)
42             if len(meta_dir_contents) > 1:
43                 # if there are any files left other than 'conda-meta/history'
44                 #   then don't unregister
45                 return
46 
47     _clean_environments_txt(USER_ENVIRONMENTS_TXT_FILE, location)
48 
49 
50 def list_all_known_prefixes():
51     all_env_paths = set()
52     if on_win:
53         home_dir_dir = dirname(expand('~'))
54         for home_dir in listdir(home_dir_dir):
55             environments_txt_file = join(home_dir_dir, home_dir, '.conda', 'environments.txt')
56             if isfile(environments_txt_file):
57                 all_env_paths.update(_clean_environments_txt(environments_txt_file))
58     else:
59         from os import geteuid
60         from pwd import getpwall
61         if geteuid() == 0:
62             search_dirs = tuple(pwentry.pw_dir for pwentry in getpwall()) or (expand('~'),)
63         else:
64             search_dirs = (expand('~'),)
65         for home_dir in search_dirs:
66             environments_txt_file = join(home_dir, '.conda', 'environments.txt')
67             if isfile(environments_txt_file):
68                 all_env_paths.update(_clean_environments_txt(environments_txt_file))
69 
70     # in case environments.txt files aren't complete, also add all known conda environments in
71     # all envs_dirs
72     envs_dirs = (envs_dir for envs_dir in context.envs_dirs if isdir(envs_dir))
73     all_env_paths.update(path for path in (
74         join(envs_dir, name) for envs_dir in envs_dirs for name in listdir(envs_dir)
75     ) if path not in all_env_paths and is_conda_environment(path))
76 
77     all_env_paths.add(context.root_prefix)
78     return sorted(all_env_paths)
79 
80 
81 def env_name(prefix):
82     if not prefix:
83         return None
84     if paths_equal(prefix, context.root_prefix):
85         return ROOT_ENV_NAME
86     maybe_envs_dir, maybe_name = path_split(prefix)
87     for envs_dir in context.envs_dirs:
88         if paths_equal(envs_dir, maybe_envs_dir):
89             return maybe_name
90     return prefix
91 
92 
93 def _clean_environments_txt(environments_txt_file, remove_location=None):
94     if not isfile(environments_txt_file):
95         return ()
96 
97     if remove_location:
98         remove_location = normpath(remove_location)
99     environments_txt_lines = tuple(yield_lines(environments_txt_file))
100     environments_txt_lines_cleaned = tuple(
101         prefix for prefix in environments_txt_lines
102         if prefix != remove_location and is_conda_environment(prefix)
103     )
104     if environments_txt_lines_cleaned != environments_txt_lines:
105         _rewrite_environments_txt(environments_txt_file, environments_txt_lines_cleaned)
106     return environments_txt_lines_cleaned
107 
108 
109 def _rewrite_environments_txt(environments_txt_file, prefixes):
110     try:
111         with open(environments_txt_file, 'w') as fh:
112             fh.write('\n'.join(prefixes))
113             fh.write('\n')
114     except (IOError, OSError) as e:
115         log.info("File not cleaned: %s", environments_txt_file)
116         log.debug('%r', e, exc_info=True)
117
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/conda/core/envs_manager.py b/conda/core/envs_manager.py
--- a/conda/core/envs_manager.py
+++ b/conda/core/envs_manager.py
@@ -7,7 +7,7 @@
 
 from ..base.constants import ROOT_ENV_NAME
 from ..base.context import context
-from ..common.compat import on_win
+from ..common.compat import ensure_text_type, on_win, open
 from ..common.path import expand, paths_equal
 from ..gateways.disk.read import yield_lines
 from ..gateways.disk.test import is_conda_environment
@@ -30,7 +30,7 @@
         return
 
     with open(USER_ENVIRONMENTS_TXT_FILE, 'a') as fh:
-        fh.write(location)
+        fh.write(ensure_text_type(location))
         fh.write('\n')
 
 
diff --git a/conda/gateways/disk/read.py b/conda/gateways/disk/read.py
--- a/conda/gateways/disk/read.py
+++ b/conda/gateways/disk/read.py
@@ -19,7 +19,7 @@
 from ..._vendor.auxlib.collection import first
 from ..._vendor.auxlib.ish import dals
 from ...base.constants import PREFIX_PLACEHOLDER
-from ...common.compat import ensure_text_type
+from ...common.compat import ensure_text_type, open
 from ...exceptions import CondaUpgradeError, CondaVerificationError, PathNotFoundError
 from ...models.channel import Channel
 from ...models.enums import FileMode, PathType

{"golden_diff": "diff --git a/conda/core/envs_manager.py b/conda/core/envs_manager.py\n--- a/conda/core/envs_manager.py\n+++ b/conda/core/envs_manager.py\n@@ -7,7 +7,7 @@\n \n from ..base.constants import ROOT_ENV_NAME\n from ..base.context import context\n-from ..common.compat import on_win\n+from ..common.compat import ensure_text_type, on_win, open\n from ..common.path import expand, paths_equal\n from ..gateways.disk.read import yield_lines\n from ..gateways.disk.test import is_conda_environment\n@@ -30,7 +30,7 @@\n         return\n \n     with open(USER_ENVIRONMENTS_TXT_FILE, 'a') as fh:\n-        fh.write(location)\n+        fh.write(ensure_text_type(location))\n         fh.write('\\n')\n \n \ndiff --git a/conda/gateways/disk/read.py b/conda/gateways/disk/read.py\n--- a/conda/gateways/disk/read.py\n+++ b/conda/gateways/disk/read.py\n@@ -19,7 +19,7 @@\n from ..._vendor.auxlib.collection import first\n from ..._vendor.auxlib.ish import dals\n from ...base.constants import PREFIX_PLACEHOLDER\n-from ...common.compat import ensure_text_type\n+from ...common.compat import ensure_text_type, open\n from ...exceptions import CondaUpgradeError, CondaVerificationError, PathNotFoundError\n from ...models.channel import Channel\n from ...models.enums import FileMode, PathType\n", "issue": "python 2 can't read unicode in environments.txt\non a conda install operation, during the transaction\r\n\r\n```\r\nTraceback (most recent call last):\r\n  File \"/Users/kfranz/continuum/conda/conda/core/link.py\", line 535, in _execute_actions\r\n    action.execute()\r\n  File \"/Users/kfranz/continuum/conda/conda/core/path_actions.py\", line 876, in execute\r\n    register_env(self.target_prefix)\r\n  File \"/Users/kfranz/continuum/conda/conda/core/envs_manager.py\", line 28, in register_env\r\n    if location in yield_lines(USER_ENVIRONMENTS_TXT_FILE):\r\n  File \"/Users/kfranz/continuum/conda/conda/gateways/disk/read.py\", line 49, in yield_lines\r\n    if not line or line.startswith('#'):\r\nUnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 54: ordinal not in range(128)\r\n```\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nfrom base64 import b64encode\nfrom collections import namedtuple\nfrom errno import ENOENT\nfrom functools import partial\nfrom glob import glob\nimport hashlib\nfrom itertools import chain\nimport json\nfrom logging import getLogger\nfrom os import listdir\nfrom os.path import isdir, isfile, join\nimport shlex\nimport tarfile\n\nfrom .link import islink, lexists\nfrom ..._vendor.auxlib.collection import first\nfrom ..._vendor.auxlib.ish import dals\nfrom ...base.constants import PREFIX_PLACEHOLDER\nfrom ...common.compat import ensure_text_type\nfrom ...exceptions import CondaUpgradeError, CondaVerificationError, PathNotFoundError\nfrom ...models.channel import Channel\nfrom ...models.enums import FileMode, PathType\nfrom ...models.index_record import IndexJsonRecord, IndexRecord, PathData, PathDataV1, PathsData\nfrom ...models.package_info import PackageInfo, PackageMetadata\n\nlog = getLogger(__name__)\n\nlistdir = listdir\nlexists, isdir, isfile = lexists, isdir, isfile\n\n\ndef yield_lines(path):\n    \"\"\"Generator function for lines in file.  Empty generator if path does not exist.\n\n    Args:\n        path (str): path to file\n\n    Returns:\n        iterator: each line in file, not starting with '#'\n\n    \"\"\"\n    try:\n        with open(path) as fh:\n            for line in fh:\n                line = line.strip()\n                if not line or line.startswith('#'):\n                    continue\n                yield line\n    except (IOError, OSError) as e:\n        if e.errno == ENOENT:\n            pass\n        else:\n            raise\n\n\ndef _digest_path(algo, path):\n    if not isfile(path):\n        raise PathNotFoundError(path)\n\n    hasher = hashlib.new(algo)\n    with open(path, \"rb\") as fh:\n        for chunk in iter(partial(fh.read, 8192), b''):\n            hasher.update(chunk)\n    return hasher.hexdigest()\n\n\ndef compute_md5sum(file_full_path):\n    return _digest_path('md5', file_full_path)\n\n\ndef compute_sha256sum(file_full_path):\n    return _digest_path('sha256', file_full_path)\n\n\ndef find_first_existing(*globs):\n    for g in globs:\n        for path in glob(g):\n            if lexists(path):\n                return path\n    return None\n\n\n# ####################################################\n# functions supporting read_package_info()\n# ####################################################\n\ndef read_package_info(record, package_cache_record):\n    epd = package_cache_record.extracted_package_dir\n    index_json_record = read_index_json(epd)\n    icondata = read_icondata(epd)\n    package_metadata = read_package_metadata(epd)\n    paths_data = read_paths_json(epd)\n\n    return PackageInfo(\n        extracted_package_dir=epd,\n        channel=Channel(record.schannel or record.channel),\n        repodata_record=record,\n        url=package_cache_record.url,\n\n        index_json_record=index_json_record,\n        icondata=icondata,\n        package_metadata=package_metadata,\n        paths_data=paths_data,\n    )\n\n\ndef read_index_json(extracted_package_directory):\n    with open(join(extracted_package_directory, 'info', 'index.json')) as fi:\n        record = IndexJsonRecord(**json.load(fi))\n    return record\n\n\ndef read_index_json_from_tarball(package_tarball_full_path):\n    with tarfile.open(package_tarball_full_path) as tf:\n        contents = tf.extractfile('info/index.json').read()\n        return IndexJsonRecord(**json.loads(ensure_text_type(contents)))\n\n\ndef read_repodata_json(extracted_package_directory):\n    with open(join(extracted_package_directory, 'info', 'repodata_record.json')) as fi:\n        record = IndexRecord(**json.load(fi))\n    return record\n\n\ndef read_icondata(extracted_package_directory):\n    icon_file_path = join(extracted_package_directory, 'info', 'icon.png')\n    if isfile(icon_file_path):\n        with open(icon_file_path, 'rb') as f:\n            data = f.read()\n        return b64encode(data).decode('utf-8')\n    else:\n        return None\n\n\ndef read_package_metadata(extracted_package_directory):\n    def _paths():\n        yield join(extracted_package_directory, 'info', 'link.json')\n        yield join(extracted_package_directory, 'info', 'package_metadata.json')\n\n    path = first(_paths(), key=isfile)\n    if not path:\n        return None\n    else:\n        with open(path, 'r') as f:\n            package_metadata = PackageMetadata(**json.loads(f.read()))\n            if package_metadata.package_metadata_version != 1:\n                raise CondaUpgradeError(dals(\"\"\"\n                The current version of conda is too old to install this package. (This version\n                only supports link.json schema version 1.)  Please update conda to install\n                this package.\"\"\"))\n        return package_metadata\n\n\ndef read_paths_json(extracted_package_directory):\n    info_dir = join(extracted_package_directory, 'info')\n    paths_json_path = join(info_dir, 'paths.json')\n    if isfile(paths_json_path):\n        with open(paths_json_path) as paths_json:\n            data = json.load(paths_json)\n        if data.get('paths_version') != 1:\n            raise CondaUpgradeError(dals(\"\"\"\n            The current version of conda is too old to install this package. (This version\n            only supports paths.json schema version 1.)  Please update conda to install\n            this package.\"\"\"))\n        paths_data = PathsData(\n            paths_version=1,\n            paths=(PathDataV1(**f) for f in data['paths']),\n        )\n    else:\n        has_prefix_files = read_has_prefix(join(info_dir, 'has_prefix'))\n        no_link = read_no_link(info_dir)\n\n        def read_files_file():\n            files_path = join(info_dir, 'files')\n            for f in (ln for ln in (line.strip() for line in yield_lines(files_path)) if ln):\n                path_info = {\"_path\": f}\n                if f in has_prefix_files.keys():\n                    path_info[\"prefix_placeholder\"] = has_prefix_files[f][0]\n                    path_info[\"file_mode\"] = has_prefix_files[f][1]\n                if f in no_link:\n                    path_info[\"no_link\"] = True\n                if islink(join(extracted_package_directory, f)):\n                    path_info[\"path_type\"] = PathType.softlink\n                else:\n                    path_info[\"path_type\"] = PathType.hardlink\n                yield PathData(**path_info)\n\n        paths = tuple(read_files_file())\n        paths_data = PathsData(\n            paths_version=0,\n            paths=paths,\n        )\n    return paths_data\n\n\ndef read_has_prefix(path):\n    \"\"\"\n    reads `has_prefix` file and return dict mapping filepaths to tuples(placeholder, FileMode)\n\n    A line in `has_prefix` contains one of\n      * filepath\n      * placeholder mode filepath\n\n    mode values are one of\n      * text\n      * binary\n    \"\"\"\n    ParseResult = namedtuple('ParseResult', ('placeholder', 'filemode', 'filepath'))\n\n    def parse_line(line):\n        # placeholder, filemode, filepath\n        parts = tuple(x.strip('\"\\'') for x in shlex.split(line, posix=False))\n        if len(parts) == 1:\n            return ParseResult(PREFIX_PLACEHOLDER, FileMode.text, parts[0])\n        elif len(parts) == 3:\n            return ParseResult(parts[0], FileMode(parts[1]), parts[2])\n        else:\n            raise CondaVerificationError(\"Invalid has_prefix file at path: %s\" % path)\n\n    parsed_lines = (parse_line(line) for line in yield_lines(path))\n    return {pr.filepath: (pr.placeholder, pr.filemode) for pr in parsed_lines}\n\n\ndef read_no_link(info_dir):\n    return set(chain(yield_lines(join(info_dir, 'no_link')),\n                     yield_lines(join(info_dir, 'no_softlink'))))\n\n\ndef read_soft_links(extracted_package_directory, files):\n    return tuple(f for f in files if islink(join(extracted_package_directory, f)))\n", "path": "conda/gateways/disk/read.py"}, {"content": "# -*- coding: utf-8 -*-\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nfrom logging import getLogger\nfrom os import listdir\nfrom os.path import dirname, isdir, isfile, join, normpath, split as path_split\n\nfrom ..base.constants import ROOT_ENV_NAME\nfrom ..base.context import context\nfrom ..common.compat import on_win\nfrom ..common.path import expand, paths_equal\nfrom ..gateways.disk.read import yield_lines\nfrom ..gateways.disk.test import is_conda_environment\n\nlog = getLogger(__name__)\n\n\nUSER_ENVIRONMENTS_TXT_FILE = expand(join('~', '.conda', 'environments.txt'))\n\n\ndef register_env(location):\n    location = normpath(location)\n\n    if \"placehold_pl\" in location:\n        # Don't record envs created by conda-build.\n        return\n\n    if location in yield_lines(USER_ENVIRONMENTS_TXT_FILE):\n        # Nothing to do. Location is already recorded in a known environments.txt file.\n        return\n\n    with open(USER_ENVIRONMENTS_TXT_FILE, 'a') as fh:\n        fh.write(location)\n        fh.write('\\n')\n\n\ndef unregister_env(location):\n    if isdir(location):\n        meta_dir = join(location, 'conda-meta')\n        if isdir(meta_dir):\n            meta_dir_contents = listdir(meta_dir)\n            if len(meta_dir_contents) > 1:\n                # if there are any files left other than 'conda-meta/history'\n                #   then don't unregister\n                return\n\n    _clean_environments_txt(USER_ENVIRONMENTS_TXT_FILE, location)\n\n\ndef list_all_known_prefixes():\n    all_env_paths = set()\n    if on_win:\n        home_dir_dir = dirname(expand('~'))\n        for home_dir in listdir(home_dir_dir):\n            environments_txt_file = join(home_dir_dir, home_dir, '.conda', 'environments.txt')\n            if isfile(environments_txt_file):\n                all_env_paths.update(_clean_environments_txt(environments_txt_file))\n    else:\n        from os import geteuid\n        from pwd import getpwall\n        if geteuid() == 0:\n            search_dirs = tuple(pwentry.pw_dir for pwentry in getpwall()) or (expand('~'),)\n        else:\n            search_dirs = (expand('~'),)\n        for home_dir in search_dirs:\n            environments_txt_file = join(home_dir, '.conda', 'environments.txt')\n            if isfile(environments_txt_file):\n                all_env_paths.update(_clean_environments_txt(environments_txt_file))\n\n    # in case environments.txt files aren't complete, also add all known conda environments in\n    # all envs_dirs\n    envs_dirs = (envs_dir for envs_dir in context.envs_dirs if isdir(envs_dir))\n    all_env_paths.update(path for path in (\n        join(envs_dir, name) for envs_dir in envs_dirs for name in listdir(envs_dir)\n    ) if path not in all_env_paths and is_conda_environment(path))\n\n    all_env_paths.add(context.root_prefix)\n    return sorted(all_env_paths)\n\n\ndef env_name(prefix):\n    if not prefix:\n        return None\n    if paths_equal(prefix, context.root_prefix):\n        return ROOT_ENV_NAME\n    maybe_envs_dir, maybe_name = path_split(prefix)\n    for envs_dir in context.envs_dirs:\n        if paths_equal(envs_dir, maybe_envs_dir):\n            return maybe_name\n    return prefix\n\n\ndef _clean_environments_txt(environments_txt_file, remove_location=None):\n    if not isfile(environments_txt_file):\n        return ()\n\n    if remove_location:\n        remove_location = normpath(remove_location)\n    environments_txt_lines = tuple(yield_lines(environments_txt_file))\n    environments_txt_lines_cleaned = tuple(\n        prefix for prefix in environments_txt_lines\n        if prefix != remove_location and is_conda_environment(prefix)\n    )\n    if environments_txt_lines_cleaned != environments_txt_lines:\n        _rewrite_environments_txt(environments_txt_file, environments_txt_lines_cleaned)\n    return environments_txt_lines_cleaned\n\n\ndef _rewrite_environments_txt(environments_txt_file, prefixes):\n    try:\n        with open(environments_txt_file, 'w') as fh:\n            fh.write('\\n'.join(prefixes))\n            fh.write('\\n')\n    except (IOError, OSError) as e:\n        log.info(\"File not cleaned: %s\", environments_txt_file)\n        log.debug('%r', e, exc_info=True)\n", "path": "conda/core/envs_manager.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nfrom base64 import b64encode\nfrom collections import namedtuple\nfrom errno import ENOENT\nfrom functools import partial\nfrom glob import glob\nimport hashlib\nfrom itertools import chain\nimport json\nfrom logging import getLogger\nfrom os import listdir\nfrom os.path import isdir, isfile, join\nimport shlex\nimport tarfile\n\nfrom .link import islink, lexists\nfrom ..._vendor.auxlib.collection import first\nfrom ..._vendor.auxlib.ish import dals\nfrom ...base.constants import PREFIX_PLACEHOLDER\nfrom ...common.compat import ensure_text_type, open\nfrom ...exceptions import CondaUpgradeError, CondaVerificationError, PathNotFoundError\nfrom ...models.channel import Channel\nfrom ...models.enums import FileMode, PathType\nfrom ...models.index_record import IndexJsonRecord, IndexRecord, PathData, PathDataV1, PathsData\nfrom ...models.package_info import PackageInfo, PackageMetadata\n\nlog = getLogger(__name__)\n\nlistdir = listdir\nlexists, isdir, isfile = lexists, isdir, isfile\n\n\ndef yield_lines(path):\n    \"\"\"Generator function for lines in file.  Empty generator if path does not exist.\n\n    Args:\n        path (str): path to file\n\n    Returns:\n        iterator: each line in file, not starting with '#'\n\n    \"\"\"\n    try:\n        with open(path) as fh:\n            for line in fh:\n                line = line.strip()\n                if not line or line.startswith('#'):\n                    continue\n                yield line\n    except (IOError, OSError) as e:\n        if e.errno == ENOENT:\n            pass\n        else:\n            raise\n\n\ndef _digest_path(algo, path):\n    if not isfile(path):\n        raise PathNotFoundError(path)\n\n    hasher = hashlib.new(algo)\n    with open(path, \"rb\") as fh:\n        for chunk in iter(partial(fh.read, 8192), b''):\n            hasher.update(chunk)\n    return hasher.hexdigest()\n\n\ndef compute_md5sum(file_full_path):\n    return _digest_path('md5', file_full_path)\n\n\ndef compute_sha256sum(file_full_path):\n    return _digest_path('sha256', file_full_path)\n\n\ndef find_first_existing(*globs):\n    for g in globs:\n        for path in glob(g):\n            if lexists(path):\n                return path\n    return None\n\n\n# ####################################################\n# functions supporting read_package_info()\n# ####################################################\n\ndef read_package_info(record, package_cache_record):\n    epd = package_cache_record.extracted_package_dir\n    index_json_record = read_index_json(epd)\n    icondata = read_icondata(epd)\n    package_metadata = read_package_metadata(epd)\n    paths_data = read_paths_json(epd)\n\n    return PackageInfo(\n        extracted_package_dir=epd,\n        channel=Channel(record.schannel or record.channel),\n        repodata_record=record,\n        url=package_cache_record.url,\n\n        index_json_record=index_json_record,\n        icondata=icondata,\n        package_metadata=package_metadata,\n        paths_data=paths_data,\n    )\n\n\ndef read_index_json(extracted_package_directory):\n    with open(join(extracted_package_directory, 'info', 'index.json')) as fi:\n        record = IndexJsonRecord(**json.load(fi))\n    return record\n\n\ndef read_index_json_from_tarball(package_tarball_full_path):\n    with tarfile.open(package_tarball_full_path) as tf:\n        contents = tf.extractfile('info/index.json').read()\n        return IndexJsonRecord(**json.loads(ensure_text_type(contents)))\n\n\ndef read_repodata_json(extracted_package_directory):\n    with open(join(extracted_package_directory, 'info', 'repodata_record.json')) as fi:\n        record = IndexRecord(**json.load(fi))\n    return record\n\n\ndef read_icondata(extracted_package_directory):\n    icon_file_path = join(extracted_package_directory, 'info', 'icon.png')\n    if isfile(icon_file_path):\n        with open(icon_file_path, 'rb') as f:\n            data = f.read()\n        return b64encode(data).decode('utf-8')\n    else:\n        return None\n\n\ndef read_package_metadata(extracted_package_directory):\n    def _paths():\n        yield join(extracted_package_directory, 'info', 'link.json')\n        yield join(extracted_package_directory, 'info', 'package_metadata.json')\n\n    path = first(_paths(), key=isfile)\n    if not path:\n        return None\n    else:\n        with open(path, 'r') as f:\n            package_metadata = PackageMetadata(**json.loads(f.read()))\n            if package_metadata.package_metadata_version != 1:\n                raise CondaUpgradeError(dals(\"\"\"\n                The current version of conda is too old to install this package. (This version\n                only supports link.json schema version 1.)  Please update conda to install\n                this package.\"\"\"))\n        return package_metadata\n\n\ndef read_paths_json(extracted_package_directory):\n    info_dir = join(extracted_package_directory, 'info')\n    paths_json_path = join(info_dir, 'paths.json')\n    if isfile(paths_json_path):\n        with open(paths_json_path) as paths_json:\n            data = json.load(paths_json)\n        if data.get('paths_version') != 1:\n            raise CondaUpgradeError(dals(\"\"\"\n            The current version of conda is too old to install this package. (This version\n            only supports paths.json schema version 1.)  Please update conda to install\n            this package.\"\"\"))\n        paths_data = PathsData(\n            paths_version=1,\n            paths=(PathDataV1(**f) for f in data['paths']),\n        )\n    else:\n        has_prefix_files = read_has_prefix(join(info_dir, 'has_prefix'))\n        no_link = read_no_link(info_dir)\n\n        def read_files_file():\n            files_path = join(info_dir, 'files')\n            for f in (ln for ln in (line.strip() for line in yield_lines(files_path)) if ln):\n                path_info = {\"_path\": f}\n                if f in has_prefix_files.keys():\n                    path_info[\"prefix_placeholder\"] = has_prefix_files[f][0]\n                    path_info[\"file_mode\"] = has_prefix_files[f][1]\n                if f in no_link:\n                    path_info[\"no_link\"] = True\n                if islink(join(extracted_package_directory, f)):\n                    path_info[\"path_type\"] = PathType.softlink\n                else:\n                    path_info[\"path_type\"] = PathType.hardlink\n                yield PathData(**path_info)\n\n        paths = tuple(read_files_file())\n        paths_data = PathsData(\n            paths_version=0,\n            paths=paths,\n        )\n    return paths_data\n\n\ndef read_has_prefix(path):\n    \"\"\"\n    reads `has_prefix` file and return dict mapping filepaths to tuples(placeholder, FileMode)\n\n    A line in `has_prefix` contains one of\n      * filepath\n      * placeholder mode filepath\n\n    mode values are one of\n      * text\n      * binary\n    \"\"\"\n    ParseResult = namedtuple('ParseResult', ('placeholder', 'filemode', 'filepath'))\n\n    def parse_line(line):\n        # placeholder, filemode, filepath\n        parts = tuple(x.strip('\"\\'') for x in shlex.split(line, posix=False))\n        if len(parts) == 1:\n            return ParseResult(PREFIX_PLACEHOLDER, FileMode.text, parts[0])\n        elif len(parts) == 3:\n            return ParseResult(parts[0], FileMode(parts[1]), parts[2])\n        else:\n            raise CondaVerificationError(\"Invalid has_prefix file at path: %s\" % path)\n\n    parsed_lines = (parse_line(line) for line in yield_lines(path))\n    return {pr.filepath: (pr.placeholder, pr.filemode) for pr in parsed_lines}\n\n\ndef read_no_link(info_dir):\n    return set(chain(yield_lines(join(info_dir, 'no_link')),\n                     yield_lines(join(info_dir, 'no_softlink'))))\n\n\ndef read_soft_links(extracted_package_directory, files):\n    return tuple(f for f in files if islink(join(extracted_package_directory, f)))\n", "path": "conda/gateways/disk/read.py"}, {"content": "# -*- coding: utf-8 -*-\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nfrom logging import getLogger\nfrom os import listdir\nfrom os.path import dirname, isdir, isfile, join, normpath, split as path_split\n\nfrom ..base.constants import ROOT_ENV_NAME\nfrom ..base.context import context\nfrom ..common.compat import ensure_text_type, on_win, open\nfrom ..common.path import expand, paths_equal\nfrom ..gateways.disk.read import yield_lines\nfrom ..gateways.disk.test import is_conda_environment\n\nlog = getLogger(__name__)\n\n\nUSER_ENVIRONMENTS_TXT_FILE = expand(join('~', '.conda', 'environments.txt'))\n\n\ndef register_env(location):\n    location = normpath(location)\n\n    if \"placehold_pl\" in location:\n        # Don't record envs created by conda-build.\n        return\n\n    if location in yield_lines(USER_ENVIRONMENTS_TXT_FILE):\n        # Nothing to do. Location is already recorded in a known environments.txt file.\n        return\n\n    with open(USER_ENVIRONMENTS_TXT_FILE, 'a') as fh:\n        fh.write(ensure_text_type(location))\n        fh.write('\\n')\n\n\ndef unregister_env(location):\n    if isdir(location):\n        meta_dir = join(location, 'conda-meta')\n        if isdir(meta_dir):\n            meta_dir_contents = listdir(meta_dir)\n            if len(meta_dir_contents) > 1:\n                # if there are any files left other than 'conda-meta/history'\n                #   then don't unregister\n                return\n\n    _clean_environments_txt(USER_ENVIRONMENTS_TXT_FILE, location)\n\n\ndef list_all_known_prefixes():\n    all_env_paths = set()\n    if on_win:\n        home_dir_dir = dirname(expand('~'))\n        for home_dir in listdir(home_dir_dir):\n            environments_txt_file = join(home_dir_dir, home_dir, '.conda', 'environments.txt')\n            if isfile(environments_txt_file):\n                all_env_paths.update(_clean_environments_txt(environments_txt_file))\n    else:\n        from os import geteuid\n        from pwd import getpwall\n        if geteuid() == 0:\n            search_dirs = tuple(pwentry.pw_dir for pwentry in getpwall()) or (expand('~'),)\n        else:\n            search_dirs = (expand('~'),)\n        for home_dir in search_dirs:\n            environments_txt_file = join(home_dir, '.conda', 'environments.txt')\n            if isfile(environments_txt_file):\n                all_env_paths.update(_clean_environments_txt(environments_txt_file))\n\n    # in case environments.txt files aren't complete, also add all known conda environments in\n    # all envs_dirs\n    envs_dirs = (envs_dir for envs_dir in context.envs_dirs if isdir(envs_dir))\n    all_env_paths.update(path for path in (\n        join(envs_dir, name) for envs_dir in envs_dirs for name in listdir(envs_dir)\n    ) if path not in all_env_paths and is_conda_environment(path))\n\n    all_env_paths.add(context.root_prefix)\n    return sorted(all_env_paths)\n\n\ndef env_name(prefix):\n    if not prefix:\n        return None\n    if paths_equal(prefix, context.root_prefix):\n        return ROOT_ENV_NAME\n    maybe_envs_dir, maybe_name = path_split(prefix)\n    for envs_dir in context.envs_dirs:\n        if paths_equal(envs_dir, maybe_envs_dir):\n            return maybe_name\n    return prefix\n\n\ndef _clean_environments_txt(environments_txt_file, remove_location=None):\n    if not isfile(environments_txt_file):\n        return ()\n\n    if remove_location:\n        remove_location = normpath(remove_location)\n    environments_txt_lines = tuple(yield_lines(environments_txt_file))\n    environments_txt_lines_cleaned = tuple(\n        prefix for prefix in environments_txt_lines\n        if prefix != remove_location and is_conda_environment(prefix)\n    )\n    if environments_txt_lines_cleaned != environments_txt_lines:\n        _rewrite_environments_txt(environments_txt_file, environments_txt_lines_cleaned)\n    return environments_txt_lines_cleaned\n\n\ndef _rewrite_environments_txt(environments_txt_file, prefixes):\n    try:\n        with open(environments_txt_file, 'w') as fh:\n            fh.write('\\n'.join(prefixes))\n            fh.write('\\n')\n    except (IOError, OSError) as e:\n        log.info(\"File not cleaned: %s\", environments_txt_file)\n        log.debug('%r', e, exc_info=True)\n", "path": "conda/core/envs_manager.py"}]}