|
1 | 1 | """ |
2 | | -This code was taken from https://github.com/ActiveState/appdirs and modified |
3 | | -to suit our purposes. |
4 | | -""" |
| 2 | +This code wraps the vendored appdirs module to so the return values are |
| 3 | +compatible for the current pip code base. |
5 | 4 |
|
6 | | -# The following comment should be removed at some point in the future. |
7 | | -# mypy: disallow-untyped-defs=False |
| 5 | +The intention is to rewrite current usages guradually, keeping the tests pass, |
| 6 | +and eventually drop this after all usages are changed. |
| 7 | +""" |
8 | 8 |
|
9 | 9 | from __future__ import absolute_import |
10 | 10 |
|
11 | 11 | import os |
12 | | -import sys |
13 | 12 |
|
14 | | -from pip._vendor.six import PY2, text_type |
| 13 | +from pip._vendor import appdirs as _appdirs |
15 | 14 |
|
16 | | -from pip._internal.utils.compat import WINDOWS, expanduser |
17 | 15 | from pip._internal.utils.typing import MYPY_CHECK_RUNNING |
18 | 16 |
|
19 | 17 | if MYPY_CHECK_RUNNING: |
|
22 | 20 |
|
23 | 21 | def user_cache_dir(appname): |
24 | 22 | # type: (str) -> str |
25 | | - r""" |
26 | | - Return full path to the user-specific cache dir for this application. |
27 | | -
|
28 | | - "appname" is the name of application. |
29 | | -
|
30 | | - Typical user cache directories are: |
31 | | - macOS: ~/Library/Caches/<AppName> |
32 | | - Unix: ~/.cache/<AppName> (XDG default) |
33 | | - Windows: C:\Users\<username>\AppData\Local\<AppName>\Cache |
34 | | -
|
35 | | - On Windows the only suggestion in the MSDN docs is that local settings go |
36 | | - in the `CSIDL_LOCAL_APPDATA` directory. This is identical to the |
37 | | - non-roaming app data dir (the default returned by `user_data_dir`). Apps |
38 | | - typically put cache data somewhere *under* the given dir here. Some |
39 | | - examples: |
40 | | - ...\Mozilla\Firefox\Profiles\<ProfileName>\Cache |
41 | | - ...\Acme\SuperApp\Cache\1.0 |
42 | | -
|
43 | | - OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value. |
44 | | - """ |
45 | | - if WINDOWS: |
46 | | - # Get the base path |
47 | | - path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA")) |
48 | | - |
49 | | - # When using Python 2, return paths as bytes on Windows like we do on |
50 | | - # other operating systems. See helper function docs for more details. |
51 | | - if PY2 and isinstance(path, text_type): |
52 | | - path = _win_path_to_bytes(path) |
53 | | - |
54 | | - # Add our app name and Cache directory to it |
55 | | - path = os.path.join(path, appname, "Cache") |
56 | | - elif sys.platform == "darwin": |
57 | | - # Get the base path |
58 | | - path = expanduser("~/Library/Caches") |
59 | | - |
60 | | - # Add our app name to it |
61 | | - path = os.path.join(path, appname) |
62 | | - else: |
63 | | - # Get the base path |
64 | | - path = os.getenv("XDG_CACHE_HOME", expanduser("~/.cache")) |
65 | | - |
66 | | - # Add our app name to it |
67 | | - path = os.path.join(path, appname) |
68 | | - |
69 | | - return path |
70 | | - |
71 | | - |
72 | | -def user_data_dir(appname, roaming=False): |
73 | | - # type: (str, bool) -> str |
74 | | - r""" |
75 | | - Return full path to the user-specific data dir for this application. |
76 | | -
|
77 | | - "appname" is the name of application. |
78 | | - If None, just the system directory is returned. |
79 | | - "roaming" (boolean, default False) can be set True to use the Windows |
80 | | - roaming appdata directory. That means that for users on a Windows |
81 | | - network setup for roaming profiles, this user data will be |
82 | | - sync'd on login. See |
83 | | - <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx> |
84 | | - for a discussion of issues. |
85 | | -
|
86 | | - Typical user data directories are: |
87 | | - macOS: ~/Library/Application Support/<AppName> |
88 | | - if it exists, else ~/.config/<AppName> |
89 | | - Unix: ~/.local/share/<AppName> # or in |
90 | | - $XDG_DATA_HOME, if defined |
91 | | - Win XP (not roaming): C:\Documents and Settings\<username>\ ... |
92 | | - ...Application Data\<AppName> |
93 | | - Win XP (roaming): C:\Documents and Settings\<username>\Local ... |
94 | | - ...Settings\Application Data\<AppName> |
95 | | - Win 7 (not roaming): C:\\Users\<username>\AppData\Local\<AppName> |
96 | | - Win 7 (roaming): C:\\Users\<username>\AppData\Roaming\<AppName> |
97 | | -
|
98 | | - For Unix, we follow the XDG spec and support $XDG_DATA_HOME. |
99 | | - That means, by default "~/.local/share/<AppName>". |
100 | | - """ |
101 | | - if WINDOWS: |
102 | | - const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA" |
103 | | - path = os.path.join(os.path.normpath(_get_win_folder(const)), appname) |
104 | | - elif sys.platform == "darwin": |
105 | | - path = os.path.join( |
106 | | - expanduser('~/Library/Application Support/'), |
107 | | - appname, |
108 | | - ) if os.path.isdir(os.path.join( |
109 | | - expanduser('~/Library/Application Support/'), |
110 | | - appname, |
111 | | - ) |
112 | | - ) else os.path.join( |
113 | | - expanduser('~/.config/'), |
114 | | - appname, |
115 | | - ) |
116 | | - else: |
117 | | - path = os.path.join( |
118 | | - os.getenv('XDG_DATA_HOME', expanduser("~/.local/share")), |
119 | | - appname, |
120 | | - ) |
121 | | - |
122 | | - return path |
| 23 | + return _appdirs.user_cache_dir(appname, appauthor=False) |
123 | 24 |
|
124 | 25 |
|
125 | 26 | def user_config_dir(appname, roaming=True): |
126 | 27 | # type: (str, bool) -> str |
127 | | - """Return full path to the user-specific config dir for this application. |
128 | | -
|
129 | | - "appname" is the name of application. |
130 | | - If None, just the system directory is returned. |
131 | | - "roaming" (boolean, default True) can be set False to not use the |
132 | | - Windows roaming appdata directory. That means that for users on a |
133 | | - Windows network setup for roaming profiles, this user data will be |
134 | | - sync'd on login. See |
135 | | - <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx> |
136 | | - for a discussion of issues. |
137 | | -
|
138 | | - Typical user data directories are: |
139 | | - macOS: same as user_data_dir |
140 | | - Unix: ~/.config/<AppName> |
141 | | - Win *: same as user_data_dir |
| 28 | + return _appdirs.user_config_dir(appname, appauthor=False, roaming=roaming) |
142 | 29 |
|
143 | | - For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME. |
144 | | - That means, by default "~/.config/<AppName>". |
145 | | - """ |
146 | | - if WINDOWS: |
147 | | - path = user_data_dir(appname, roaming=roaming) |
148 | | - elif sys.platform == "darwin": |
149 | | - path = user_data_dir(appname) |
150 | | - else: |
151 | | - path = os.getenv('XDG_CONFIG_HOME', expanduser("~/.config")) |
152 | | - path = os.path.join(path, appname) |
153 | 30 |
|
154 | | - return path |
| 31 | +def user_data_dir(appname, roaming=False): |
| 32 | + # type: (str, bool) -> str |
| 33 | + return _appdirs.user_data_dir(appname, appauthor=False, roaming=roaming) |
155 | 34 |
|
156 | 35 |
|
157 | | -# for the discussion regarding site_config_dirs locations |
158 | | -# see <https://github.com/pypa/pip/issues/1733> |
159 | 36 | def site_config_dirs(appname): |
160 | 37 | # type: (str) -> List[str] |
161 | | - r"""Return a list of potential user-shared config dirs for this application. |
162 | | -
|
163 | | - "appname" is the name of application. |
164 | | -
|
165 | | - Typical user config directories are: |
166 | | - macOS: /Library/Application Support/<AppName>/ |
167 | | - Unix: /etc or $XDG_CONFIG_DIRS[i]/<AppName>/ for each value in |
168 | | - $XDG_CONFIG_DIRS |
169 | | - Win XP: C:\Documents and Settings\All Users\Application ... |
170 | | - ...Data\<AppName>\ |
171 | | - Vista: (Fail! "C:\ProgramData" is a hidden *system* directory |
172 | | - on Vista.) |
173 | | - Win 7: Hidden, but writeable on Win 7: |
174 | | - C:\ProgramData\<AppName>\ |
175 | | - """ |
176 | | - if WINDOWS: |
177 | | - path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA")) |
178 | | - pathlist = [os.path.join(path, appname)] |
179 | | - elif sys.platform == 'darwin': |
180 | | - pathlist = [os.path.join('/Library/Application Support', appname)] |
181 | | - else: |
182 | | - # try looking in $XDG_CONFIG_DIRS |
183 | | - xdg_config_dirs = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg') |
184 | | - if xdg_config_dirs: |
185 | | - pathlist = [ |
186 | | - os.path.join(expanduser(x), appname) |
187 | | - for x in xdg_config_dirs.split(os.pathsep) |
188 | | - ] |
189 | | - else: |
190 | | - pathlist = [] |
191 | | - |
192 | | - # always look in /etc directly as well |
193 | | - pathlist.append('/etc') |
194 | | - |
195 | | - return pathlist |
196 | | - |
197 | | - |
198 | | -# -- Windows support functions -- |
199 | | - |
200 | | -def _get_win_folder_from_registry(csidl_name): |
201 | | - # type: (str) -> str |
202 | | - """ |
203 | | - This is a fallback technique at best. I'm not sure if using the |
204 | | - registry for this guarantees us the correct answer for all CSIDL_* |
205 | | - names. |
206 | | - """ |
207 | | - import _winreg |
208 | | - |
209 | | - shell_folder_name = { |
210 | | - "CSIDL_APPDATA": "AppData", |
211 | | - "CSIDL_COMMON_APPDATA": "Common AppData", |
212 | | - "CSIDL_LOCAL_APPDATA": "Local AppData", |
213 | | - }[csidl_name] |
214 | | - |
215 | | - key = _winreg.OpenKey( |
216 | | - _winreg.HKEY_CURRENT_USER, |
217 | | - r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" |
218 | | - ) |
219 | | - directory, _type = _winreg.QueryValueEx(key, shell_folder_name) |
220 | | - return directory |
221 | | - |
222 | | - |
223 | | -def _get_win_folder_with_ctypes(csidl_name): |
224 | | - # type: (str) -> str |
225 | | - # On Python 2, ctypes.create_unicode_buffer().value returns "unicode", |
226 | | - # which isn't the same as str in the annotation above. |
227 | | - csidl_const = { |
228 | | - "CSIDL_APPDATA": 26, |
229 | | - "CSIDL_COMMON_APPDATA": 35, |
230 | | - "CSIDL_LOCAL_APPDATA": 28, |
231 | | - }[csidl_name] |
232 | | - |
233 | | - buf = ctypes.create_unicode_buffer(1024) |
234 | | - windll = ctypes.windll # type: ignore |
235 | | - windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf) |
236 | | - |
237 | | - # Downgrade to short path name if have highbit chars. See |
238 | | - # <http://bugs.activestate.com/show_bug.cgi?id=85099>. |
239 | | - has_high_char = False |
240 | | - for c in buf: |
241 | | - if ord(c) > 255: |
242 | | - has_high_char = True |
243 | | - break |
244 | | - if has_high_char: |
245 | | - buf2 = ctypes.create_unicode_buffer(1024) |
246 | | - if windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024): |
247 | | - buf = buf2 |
248 | | - |
249 | | - # The type: ignore is explained under the type annotation for this function |
250 | | - return buf.value # type: ignore |
251 | | - |
252 | | - |
253 | | -if WINDOWS: |
254 | | - try: |
255 | | - import ctypes |
256 | | - _get_win_folder = _get_win_folder_with_ctypes |
257 | | - except ImportError: |
258 | | - _get_win_folder = _get_win_folder_from_registry |
259 | | - |
260 | | - |
261 | | -def _win_path_to_bytes(path): |
262 | | - """Encode Windows paths to bytes. Only used on Python 2. |
263 | | -
|
264 | | - Motivation is to be consistent with other operating systems where paths |
265 | | - are also returned as bytes. This avoids problems mixing bytes and Unicode |
266 | | - elsewhere in the codebase. For more details and discussion see |
267 | | - <https://github.com/pypa/pip/issues/3463>. |
268 | | -
|
269 | | - If encoding using ASCII and MBCS fails, return the original Unicode path. |
270 | | - """ |
271 | | - for encoding in ('ASCII', 'MBCS'): |
272 | | - try: |
273 | | - return path.encode(encoding) |
274 | | - except (UnicodeEncodeError, LookupError): |
275 | | - pass |
276 | | - return path |
| 38 | + dirval = _appdirs.site_config_dir(appname, appauthor=False, multipath=True) |
| 39 | + if _appdirs.system == "linux2": |
| 40 | + return dirval.split(os.pathsep) |
| 41 | + return [dirval] |
0 commit comments