Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(19)

Delta Between Two Patch Sets: Lib/os.py

Issue 16353: add function to os module for getting path to default shell
Left Patch Set: Created 5 years, 6 months ago
Right Patch Set: Created 4 years ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | Modules/posixmodule.c » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 r"""OS routines for NT or Posix depending on what system we're on. 1 r"""OS routines for NT or Posix depending on what system we're on.
2 2
3 This exports: 3 This exports:
4 - all functions from posix, nt or ce, e.g. unlink, stat, etc. 4 - all functions from posix, nt or ce, e.g. unlink, stat, etc.
5 - os.path is either posixpath or ntpath 5 - os.path is either posixpath or ntpath
6 - os.name is either 'posix', 'nt' or 'ce'. 6 - os.name is either 'posix', 'nt' or 'ce'.
7 - os.curdir is a string representing the current directory ('.' or ':') 7 - os.curdir is a string representing the current directory ('.' or ':')
8 - os.pardir is a string representing the parent directory ('..' or '::') 8 - os.pardir is a string representing the parent directory ('..' or '::')
9 - os.sep is the (or a most common) pathname separator ('/' or ':' or '\\') 9 - os.sep is the (or a most common) pathname separator ('/' or ':' or '\\')
10 - os.extsep is the extension separator (always '.') 10 - os.extsep is the extension separator (always '.')
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 _add("HAVE_UTIMENSAT", "utime") 196 _add("HAVE_UTIMENSAT", "utime")
197 _add("MS_WINDOWS", "stat") 197 _add("MS_WINDOWS", "stat")
198 supports_follow_symlinks = _set 198 supports_follow_symlinks = _set
199 199
200 del _set 200 del _set
201 del _have_functions 201 del _have_functions
202 del _globals 202 del _globals
203 del _add 203 del _add
204 204
205 205
206 if sys.platform == 'win32':
207 default_shell = 'cmd.exe'
Michael.Felt 2016/07/29 14:40:15 Has cmd.exe moved around too much to not specify a
eryksun 2016/07/29 15:03:28 It should be environ['ComSpec'], for which the def
208 elif _exists('is_android') and is_android:
209 default_shell = '/system/bin/sh'
210 else:
211 default_shell = '/bin/sh'
212
206 # Python uses fixed values for the SEEK_ constants; they are mapped 213 # Python uses fixed values for the SEEK_ constants; they are mapped
207 # to native constants if necessary in posixmodule.c 214 # to native constants if necessary in posixmodule.c
208 # Other possible SEEK values are directly imported from posixmodule.c 215 # Other possible SEEK values are directly imported from posixmodule.c
209 SEEK_SET = 0 216 SEEK_SET = 0
210 SEEK_CUR = 1 217 SEEK_CUR = 1
211 SEEK_END = 2 218 SEEK_END = 2
212 219
213 # Super directory utilities. 220 # Super directory utilities.
214 # (Inspired by Eric Raymond; the doc strings are mostly his) 221 # (Inspired by Eric Raymond; the doc strings are mostly his)
215 222
216 def makedirs(name, mode=0o777, exist_ok=False): 223 def makedirs(name, mode=0o777, exist_ok=False):
217 """makedirs(name [, mode=0o777][, exist_ok=False]) 224 """makedirs(name [, mode=0o777][, exist_ok=False])
218 225
219 Super-mkdir; create a leaf directory and all intermediate ones. Works like 226 Super-mkdir; create a leaf directory and all intermediate ones. Works like
220 mkdir, except that any intermediate path segment (not just the rightmost) 227 mkdir, except that any intermediate path segment (not just the rightmost)
221 will be created if it does not exist. If the target directory already 228 will be created if it does not exist. If the target directory already
222 exists, raise an OSError if exist_ok is False. Otherwise no exception is 229 exists, raise an OSError if exist_ok is False. Otherwise no exception is
223 raised. This is recursive. 230 raised. This is recursive.
224 231
225 """ 232 """
226 head, tail = path.split(name) 233 head, tail = path.split(name)
227 if not tail: 234 if not tail:
228 head, tail = path.split(head) 235 head, tail = path.split(head)
229 if head and tail and not path.exists(head): 236 if head and tail and not path.exists(head):
230 try: 237 try:
231 makedirs(head, mode, exist_ok) 238 makedirs(head, mode, exist_ok)
232 except FileExistsError: 239 except FileExistsError:
233 # be happy if someone already created the path 240 # Defeats race condition when another thread created the path
234 pass 241 pass
235 cdir = curdir 242 cdir = curdir
236 if isinstance(tail, bytes): 243 if isinstance(tail, bytes):
237 cdir = bytes(curdir, 'ASCII') 244 cdir = bytes(curdir, 'ASCII')
238 if tail == cdir: # xxx/newdir/. exists if xxx/newdir exists 245 if tail == cdir: # xxx/newdir/. exists if xxx/newdir exists
239 return 246 return
240 try: 247 try:
241 mkdir(name, mode) 248 mkdir(name, mode)
242 except OSError as e: 249 except OSError:
243 if not exist_ok or e.errno != errno.EEXIST or not path.isdir(name): 250 # Cannot rely on checking for EEXIST, since the operating system
251 # could give priority to other errors like EACCES or EROFS
252 if not exist_ok or not path.isdir(name):
244 raise 253 raise
245 254
246 def removedirs(name): 255 def removedirs(name):
247 """removedirs(name) 256 """removedirs(name)
248 257
249 Super-rmdir; remove a leaf directory and all empty intermediate 258 Super-rmdir; remove a leaf directory and all empty intermediate
250 ones. Works like rmdir except that, if the leaf directory is 259 ones. Works like rmdir except that, if the leaf directory is
251 successfully removed, directories corresponding to rightmost path 260 successfully removed, directories corresponding to rightmost path
252 segments will be pruned away until either the whole path is 261 segments will be pruned away until either the whole path is
253 consumed or an error occurs. Errors during this latter phase are 262 consumed or an error occurs. Errors during this latter phase are
(...skipping 11 matching lines...) Expand all
265 break 274 break
266 head, tail = path.split(head) 275 head, tail = path.split(head)
267 276
268 def renames(old, new): 277 def renames(old, new):
269 """renames(old, new) 278 """renames(old, new)
270 279
271 Super-rename; create directories as necessary and delete any left 280 Super-rename; create directories as necessary and delete any left
272 empty. Works like rename, except creation of any intermediate 281 empty. Works like rename, except creation of any intermediate
273 directories needed to make the new pathname good is attempted 282 directories needed to make the new pathname good is attempted
274 first. After the rename, directories corresponding to rightmost 283 first. After the rename, directories corresponding to rightmost
275 path segments of the old name will be pruned way until either the 284 path segments of the old name will be pruned until either the
276 whole path is consumed or a nonempty directory is found. 285 whole path is consumed or a nonempty directory is found.
277 286
278 Note: this function can fail with the new directory structure made 287 Note: this function can fail with the new directory structure made
279 if you lack permissions needed to unlink the leaf directory or 288 if you lack permissions needed to unlink the leaf directory or
280 file. 289 file.
281 290
282 """ 291 """
283 head, tail = path.split(new) 292 head, tail = path.split(new)
284 if head and tail and not path.exists(head): 293 if head and tail and not path.exists(head):
285 makedirs(head) 294 makedirs(head)
(...skipping 30 matching lines...) Expand all
316 325
317 When topdown is true, the caller can modify the dirnames list in-place 326 When topdown is true, the caller can modify the dirnames list in-place
318 (e.g., via del or slice assignment), and walk will only recurse into the 327 (e.g., via del or slice assignment), and walk will only recurse into the
319 subdirectories whose names remain in dirnames; this can be used to prune the 328 subdirectories whose names remain in dirnames; this can be used to prune the
320 search, or to impose a specific order of visiting. Modifying dirnames when 329 search, or to impose a specific order of visiting. Modifying dirnames when
321 topdown is false is ineffective, since the directories in dirnames have 330 topdown is false is ineffective, since the directories in dirnames have
322 already been generated by the time dirnames itself is generated. No matter 331 already been generated by the time dirnames itself is generated. No matter
323 the value of topdown, the list of subdirectories is retrieved before the 332 the value of topdown, the list of subdirectories is retrieved before the
324 tuples for the directory and its subdirectories are generated. 333 tuples for the directory and its subdirectories are generated.
325 334
326 By default errors from the os.listdir() call are ignored. If 335 By default errors from the os.scandir() call are ignored. If
327 optional arg 'onerror' is specified, it should be a function; it 336 optional arg 'onerror' is specified, it should be a function; it
328 will be called with one argument, an OSError instance. It can 337 will be called with one argument, an OSError instance. It can
329 report the error to continue with the walk, or raise the exception 338 report the error to continue with the walk, or raise the exception
330 to abort the walk. Note that the filename is available as the 339 to abort the walk. Note that the filename is available as the
331 filename attribute of the exception object. 340 filename attribute of the exception object.
332 341
333 By default, os.walk does not follow symbolic links to subdirectories on 342 By default, os.walk does not follow symbolic links to subdirectories on
334 systems that support them. In order to get this functionality, set the 343 systems that support them. In order to get this functionality, set the
335 optional argument 'followlinks' to true. 344 optional argument 'followlinks' to true.
336 345
337 Caution: if you pass a relative pathname for top, don't change the 346 Caution: if you pass a relative pathname for top, don't change the
338 current working directory between resumptions of walk. walk never 347 current working directory between resumptions of walk. walk never
339 changes the current directory, and assumes that the client doesn't 348 changes the current directory, and assumes that the client doesn't
340 either. 349 either.
341 350
342 Example: 351 Example:
343 352
344 import os 353 import os
345 from os.path import join, getsize 354 from os.path import join, getsize
346 for root, dirs, files in os.walk('python/Lib/email'): 355 for root, dirs, files in os.walk('python/Lib/email'):
347 print(root, "consumes", end="") 356 print(root, "consumes", end="")
348 print(sum([getsize(join(root, name)) for name in files]), end="") 357 print(sum([getsize(join(root, name)) for name in files]), end="")
349 print("bytes in", len(files), "non-directory files") 358 print("bytes in", len(files), "non-directory files")
350 if 'CVS' in dirs: 359 if 'CVS' in dirs:
351 dirs.remove('CVS') # don't visit CVS directories 360 dirs.remove('CVS') # don't visit CVS directories
352 361
353 """ 362 """
354 363
355 islink, join, isdir = path.islink, path.join, path.isdir 364 dirs = []
365 nondirs = []
366 walk_dirs = []
356 367
357 # We may not have read permission for top, in which case we can't 368 # We may not have read permission for top, in which case we can't
358 # get a list of the files the directory contains. os.walk 369 # get a list of the files the directory contains. os.walk
359 # always suppressed the exception then, rather than blow up for a 370 # always suppressed the exception then, rather than blow up for a
360 # minor reason when (say) a thousand readable directories are still 371 # minor reason when (say) a thousand readable directories are still
361 # left to visit. That logic is copied here. 372 # left to visit. That logic is copied here.
362 try: 373 try:
363 # Note that listdir is global in this module due 374 if name == 'nt' and isinstance(top, bytes):
364 # to earlier import-*. 375 scandir_it = _dummy_scandir(top)
365 names = listdir(top) 376 else:
366 except OSError as err: 377 # Note that scandir is global in this module due
378 # to earlier import-*.
379 scandir_it = scandir(top)
380 except OSError as error:
367 if onerror is not None: 381 if onerror is not None:
368 onerror(err) 382 onerror(error)
369 return 383 return
370 384
371 dirs, nondirs = [], [] 385 with scandir_it:
372 for name in names: 386 while True:
373 if isdir(join(top, name)): 387 try:
374 dirs.append(name) 388 try:
375 else: 389 entry = next(scandir_it)
376 nondirs.append(name) 390 except StopIteration:
377 391 break
392 except OSError as error:
393 if onerror is not None:
394 onerror(error)
395 return
396
397 try:
398 is_dir = entry.is_dir()
399 except OSError:
400 # If is_dir() raises an OSError, consider that the entry is not
401 # a directory, same behaviour than os.path.isdir().
402 is_dir = False
403
404 if is_dir:
405 dirs.append(entry.name)
406 else:
407 nondirs.append(entry.name)
408
409 if not topdown and is_dir:
410 # Bottom-up: recurse into sub-directory, but exclude symlinks to
411 # directories if followlinks is False
412 if followlinks:
413 walk_into = True
414 else:
415 try:
416 is_symlink = entry.is_symlink()
417 except OSError:
418 # If is_symlink() raises an OSError, consider that the
419 # entry is not a symbolic link, same behaviour than
420 # os.path.islink().
421 is_symlink = False
422 walk_into = not is_symlink
423
424 if walk_into:
425 walk_dirs.append(entry.path)
426
427 # Yield before recursion if going top down
378 if topdown: 428 if topdown:
379 yield top, dirs, nondirs 429 yield top, dirs, nondirs
380 for name in dirs: 430
381 new_path = join(top, name) 431 # Recurse into sub-directories
382 if followlinks or not islink(new_path): 432 islink, join = path.islink, path.join
433 for dirname in dirs:
434 new_path = join(top, dirname)
435 # Issue #23605: os.path.islink() is used instead of caching
436 # entry.is_symlink() result during the loop on os.scandir() because
437 # the caller can replace the directory entry during the "yield"
438 # above.
439 if followlinks or not islink(new_path):
440 yield from walk(new_path, topdown, onerror, followlinks)
441 else:
442 # Recurse into sub-directories
443 for new_path in walk_dirs:
383 yield from walk(new_path, topdown, onerror, followlinks) 444 yield from walk(new_path, topdown, onerror, followlinks)
384 if not topdown: 445 # Yield after recursion if going bottom up
385 yield top, dirs, nondirs 446 yield top, dirs, nondirs
447
448 class _DummyDirEntry:
449 """Dummy implementation of DirEntry
450
451 Only used internally by os.walk(bytes). Since os.walk() doesn't need the
452 follow_symlinks parameter: don't implement it, always follow symbolic
453 links.
454 """
455
456 def __init__(self, dir, name):
457 self.name = name
458 self.path = path.join(dir, name)
459 # Mimick FindFirstFile/FindNextFile: we should get file attributes
460 # while iterating on a directory
461 self._stat = None
462 self._lstat = None
463 try:
464 self.stat(follow_symlinks=False)
465 except OSError:
466 pass
467
468 def stat(self, *, follow_symlinks=True):
469 if follow_symlinks:
470 if self._stat is None:
471 self._stat = stat(self.path)
472 return self._stat
473 else:
474 if self._lstat is None:
475 self._lstat = stat(self.path, follow_symlinks=False)
476 return self._lstat
477
478 def is_dir(self):
479 if self._lstat is not None and not self.is_symlink():
480 # use the cache lstat
481 stat = self.stat(follow_symlinks=False)
482 return st.S_ISDIR(stat.st_mode)
483
484 stat = self.stat()
485 return st.S_ISDIR(stat.st_mode)
486
487 def is_symlink(self):
488 stat = self.stat(follow_symlinks=False)
489 return st.S_ISLNK(stat.st_mode)
490
491 class _dummy_scandir:
492 # listdir-based implementation for bytes patches on Windows
493 def __init__(self, dir):
494 self.dir = dir
495 self.it = iter(listdir(dir))
496
497 def __iter__(self):
498 return self
499
500 def __next__(self):
501 return _DummyDirEntry(self.dir, next(self.it))
502
503 def __enter__(self):
504 return self
505
506 def __exit__(self, *args):
507 self.it = iter(())
386 508
387 __all__.append("walk") 509 __all__.append("walk")
388 510
389 if {open, stat} <= supports_dir_fd and {listdir, stat} <= supports_fd: 511 if {open, stat} <= supports_dir_fd and {listdir, stat} <= supports_fd:
390 512
391 def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir _fd=None): 513 def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir _fd=None):
392 """Directory tree generator. 514 """Directory tree generator.
393 515
394 This behaves exactly like walk(), except that it yields a 4-tuple 516 This behaves exactly like walk(), except that it yields a 4-tuple
395 517
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
461 if topdown: 583 if topdown:
462 yield toppath, dirs, nondirs, topfd 584 yield toppath, dirs, nondirs, topfd
463 585
464 for name in dirs: 586 for name in dirs:
465 try: 587 try:
466 orig_st = stat(name, dir_fd=topfd, follow_symlinks=follow_symlin ks) 588 orig_st = stat(name, dir_fd=topfd, follow_symlinks=follow_symlin ks)
467 dirfd = open(name, O_RDONLY, dir_fd=topfd) 589 dirfd = open(name, O_RDONLY, dir_fd=topfd)
468 except OSError as err: 590 except OSError as err:
469 if onerror is not None: 591 if onerror is not None:
470 onerror(err) 592 onerror(err)
471 return 593 continue
472 try: 594 try:
473 if follow_symlinks or path.samestat(orig_st, stat(dirfd)): 595 if follow_symlinks or path.samestat(orig_st, stat(dirfd)):
474 dirpath = path.join(toppath, name) 596 dirpath = path.join(toppath, name)
475 yield from _fwalk(dirfd, dirpath, topdown, onerror, follow_s ymlinks) 597 yield from _fwalk(dirfd, dirpath, topdown, onerror, follow_s ymlinks)
476 finally: 598 finally:
477 close(dirfd) 599 close(dirfd)
478 600
479 if not topdown: 601 if not topdown:
480 yield toppath, dirs, nondirs, topfd 602 yield toppath, dirs, nondirs, topfd
481 603
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
607 raise ValueError( 729 raise ValueError(
608 "env cannot contain 'PATH' and b'PATH' keys") 730 "env cannot contain 'PATH' and b'PATH' keys")
609 path_list = path_listb 731 path_list = path_listb
610 732
611 if path_list is not None and isinstance(path_list, bytes): 733 if path_list is not None and isinstance(path_list, bytes):
612 path_list = fsdecode(path_list) 734 path_list = fsdecode(path_list)
613 735
614 if path_list is None: 736 if path_list is None:
615 path_list = defpath 737 path_list = defpath
616 return path_list.split(pathsep) 738 return path_list.split(pathsep)
617
618
619 if sys.platform == "win32":
620 def get_shell_executable():
621 """Return path to the command processor specified by %ComSpec%.
622
623 Default: %SystemRoot%\system32\cmd.exe
624 """
625 return (environ.get('ComSpec') or
626 path.join(environ.get('SystemRoot', r'C:\Windows'),
627 r'system32\cmd.exe'))
628 else: # POSIX
629 def get_shell_executable():
630 """Return path to the standard system shell executable.
631
632 Default: '/bin/sh'
633 """
634 for dirpath in defpath.split(pathsep):
635 if dirpath: # exclude '' (cwd)
636 sh = path.join(dirpath, 'sh')
637 if access(sh, F_OK | X_OK) and path.isfile(sh):
638 #NOTE: allow symlinks e.g., /bin/sh on Ubuntu may be dash
639 return sh
640 # normally, we should not get here, defpath should contain the
641 # path to the standard shell
642 return '/bin/sh'
643 739
644 740
645 # Change environ to automatically call putenv(), unsetenv if they exist. 741 # Change environ to automatically call putenv(), unsetenv if they exist.
646 from _collections_abc import MutableMapping 742 from _collections_abc import MutableMapping
647 743
648 class _Environ(MutableMapping): 744 class _Environ(MutableMapping):
649 def __init__(self, data, encodekey, decodekey, encodevalue, decodevalue, put env, unsetenv): 745 def __init__(self, data, encodekey, decodekey, encodevalue, decodevalue, put env, unsetenv):
650 self.encodekey = encodekey 746 self.encodekey = encodekey
651 self.decodekey = decodekey 747 self.decodekey = decodekey
652 self.encodevalue = encodevalue 748 self.encodevalue = encodevalue
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after
1001 return getattr(self._stream, name) 1097 return getattr(self._stream, name)
1002 def __iter__(self): 1098 def __iter__(self):
1003 return iter(self._stream) 1099 return iter(self._stream)
1004 1100
1005 # Supply os.fdopen() 1101 # Supply os.fdopen()
1006 def fdopen(fd, *args, **kwargs): 1102 def fdopen(fd, *args, **kwargs):
1007 if not isinstance(fd, int): 1103 if not isinstance(fd, int):
1008 raise TypeError("invalid fd type (%s, expected integer)" % type(fd)) 1104 raise TypeError("invalid fd type (%s, expected integer)" % type(fd))
1009 import io 1105 import io
1010 return io.open(fd, *args, **kwargs) 1106 return io.open(fd, *args, **kwargs)
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+