145 return iter(self._fp) |
150 return iter(self._fp) |
146 |
151 |
147 def __getattr__(self, name): |
152 def __getattr__(self, name): |
148 return getattr(self._fp, name) |
153 return getattr(self._fp, name) |
149 |
154 |
|
155 |
150 def posixfile(name, mode='r', buffering=-1): |
156 def posixfile(name, mode='r', buffering=-1): |
151 '''Open a file with even more POSIX-like semantics''' |
157 '''Open a file with even more POSIX-like semantics''' |
152 try: |
158 try: |
153 fp = osutil.posixfile(name, mode, buffering) # may raise WindowsError |
159 fp = osutil.posixfile(name, mode, buffering) # may raise WindowsError |
154 |
160 |
155 # PyFile_FromFd() ignores the name, and seems to report fp.name as the |
161 # PyFile_FromFd() ignores the name, and seems to report fp.name as the |
156 # underlying file descriptor. |
162 # underlying file descriptor. |
157 if pycompat.ispy3: |
163 if pycompat.ispy3: |
158 fp = fdproxy(name, fp) |
164 fp = fdproxy(name, fp) |
166 return mixedfilemodewrapper(fp) |
172 return mixedfilemodewrapper(fp) |
167 |
173 |
168 return fp |
174 return fp |
169 except WindowsError as err: |
175 except WindowsError as err: |
170 # convert to a friendlier exception |
176 # convert to a friendlier exception |
171 raise IOError(err.errno, r'%s: %s' % ( |
177 raise IOError( |
172 encoding.strfromlocal(name), err.strerror)) |
178 err.errno, r'%s: %s' % (encoding.strfromlocal(name), err.strerror) |
|
179 ) |
|
180 |
173 |
181 |
174 # may be wrapped by win32mbcs extension |
182 # may be wrapped by win32mbcs extension |
175 listdir = osutil.listdir |
183 listdir = osutil.listdir |
|
184 |
176 |
185 |
177 class winstdout(object): |
186 class winstdout(object): |
178 '''stdout on windows misbehaves if sent through a pipe''' |
187 '''stdout on windows misbehaves if sent through a pipe''' |
179 |
188 |
180 def __init__(self, fp): |
189 def __init__(self, fp): |
213 except IOError as inst: |
222 except IOError as inst: |
214 if not win32.lasterrorwaspipeerror(inst): |
223 if not win32.lasterrorwaspipeerror(inst): |
215 raise |
224 raise |
216 raise IOError(errno.EPIPE, r'Broken pipe') |
225 raise IOError(errno.EPIPE, r'Broken pipe') |
217 |
226 |
|
227 |
218 def _is_win_9x(): |
228 def _is_win_9x(): |
219 '''return true if run on windows 95, 98 or me.''' |
229 '''return true if run on windows 95, 98 or me.''' |
220 try: |
230 try: |
221 return sys.getwindowsversion()[3] == 1 |
231 return sys.getwindowsversion()[3] == 1 |
222 except AttributeError: |
232 except AttributeError: |
223 return 'command' in encoding.environ.get('comspec', '') |
233 return 'command' in encoding.environ.get('comspec', '') |
224 |
234 |
|
235 |
225 def openhardlinks(): |
236 def openhardlinks(): |
226 return not _is_win_9x() |
237 return not _is_win_9x() |
|
238 |
227 |
239 |
228 def parsepatchoutput(output_line): |
240 def parsepatchoutput(output_line): |
229 """parses the output produced by patch and returns the filename""" |
241 """parses the output produced by patch and returns the filename""" |
230 pf = output_line[14:] |
242 pf = output_line[14:] |
231 if pf[0] == '`': |
243 if pf[0] == '`': |
232 pf = pf[1:-1] # Remove the quotes |
244 pf = pf[1:-1] # Remove the quotes |
233 return pf |
245 return pf |
|
246 |
234 |
247 |
235 def sshargs(sshcmd, host, user, port): |
248 def sshargs(sshcmd, host, user, port): |
236 '''Build argument list for ssh or Plink''' |
249 '''Build argument list for ssh or Plink''' |
237 pflag = 'plink' in sshcmd.lower() and '-P' or '-p' |
250 pflag = 'plink' in sshcmd.lower() and '-P' or '-p' |
238 args = user and ("%s@%s" % (user, host)) or host |
251 args = user and ("%s@%s" % (user, host)) or host |
239 if args.startswith('-') or args.startswith('/'): |
252 if args.startswith('-') or args.startswith('/'): |
240 raise error.Abort( |
253 raise error.Abort( |
241 _('illegal ssh hostname or username starting with - or /: %s') % |
254 _('illegal ssh hostname or username starting with - or /: %s') |
242 args) |
255 % args |
|
256 ) |
243 args = shellquote(args) |
257 args = shellquote(args) |
244 if port: |
258 if port: |
245 args = '%s %s %s' % (pflag, shellquote(port), args) |
259 args = '%s %s %s' % (pflag, shellquote(port), args) |
246 return args |
260 return args |
247 |
261 |
|
262 |
248 def setflags(f, l, x): |
263 def setflags(f, l, x): |
249 pass |
264 pass |
250 |
265 |
|
266 |
251 def copymode(src, dst, mode=None, enforcewritable=False): |
267 def copymode(src, dst, mode=None, enforcewritable=False): |
252 pass |
268 pass |
253 |
269 |
|
270 |
254 def checkexec(path): |
271 def checkexec(path): |
255 return False |
272 return False |
256 |
273 |
|
274 |
257 def checklink(path): |
275 def checklink(path): |
258 return False |
276 return False |
|
277 |
259 |
278 |
260 def setbinary(fd): |
279 def setbinary(fd): |
261 # When run without console, pipes may expose invalid |
280 # When run without console, pipes may expose invalid |
262 # fileno(), usually set to -1. |
281 # fileno(), usually set to -1. |
263 fno = getattr(fd, 'fileno', None) |
282 fno = getattr(fd, 'fileno', None) |
264 if fno is not None and fno() >= 0: |
283 if fno is not None and fno() >= 0: |
265 msvcrt.setmode(fno(), os.O_BINARY) |
284 msvcrt.setmode(fno(), os.O_BINARY) |
266 |
285 |
|
286 |
267 def pconvert(path): |
287 def pconvert(path): |
268 return path.replace(pycompat.ossep, '/') |
288 return path.replace(pycompat.ossep, '/') |
269 |
289 |
|
290 |
270 def localpath(path): |
291 def localpath(path): |
271 return path.replace('/', '\\') |
292 return path.replace('/', '\\') |
272 |
293 |
|
294 |
273 def normpath(path): |
295 def normpath(path): |
274 return pconvert(os.path.normpath(path)) |
296 return pconvert(os.path.normpath(path)) |
275 |
297 |
|
298 |
276 def normcase(path): |
299 def normcase(path): |
277 return encoding.upper(path) # NTFS compares via upper() |
300 return encoding.upper(path) # NTFS compares via upper() |
|
301 |
278 |
302 |
279 # see posix.py for definitions |
303 # see posix.py for definitions |
280 normcasespec = encoding.normcasespecs.upper |
304 normcasespec = encoding.normcasespecs.upper |
281 normcasefallback = encoding.upperfallback |
305 normcasefallback = encoding.upperfallback |
282 |
306 |
|
307 |
283 def samestat(s1, s2): |
308 def samestat(s1, s2): |
284 return False |
309 return False |
|
310 |
285 |
311 |
286 def shelltocmdexe(path, env): |
312 def shelltocmdexe(path, env): |
287 r"""Convert shell variables in the form $var and ${var} inside ``path`` |
313 r"""Convert shell variables in the form $var and ${var} inside ``path`` |
288 to %var% form. Existing Windows style variables are left unchanged. |
314 to %var% form. Existing Windows style variables are left unchanged. |
289 |
315 |
316 |
342 |
317 res = b'' |
343 res = b'' |
318 index = 0 |
344 index = 0 |
319 pathlen = len(path) |
345 pathlen = len(path) |
320 while index < pathlen: |
346 while index < pathlen: |
321 c = path[index:index + 1] |
347 c = path[index : index + 1] |
322 if c == b'\'': # no expansion within single quotes |
348 if c == b'\'': # no expansion within single quotes |
323 path = path[index + 1:] |
349 path = path[index + 1 :] |
324 pathlen = len(path) |
350 pathlen = len(path) |
325 try: |
351 try: |
326 index = path.index(b'\'') |
352 index = path.index(b'\'') |
327 res += b'"' + path[:index] + b'"' |
353 res += b'"' + path[:index] + b'"' |
328 except ValueError: |
354 except ValueError: |
329 res += c + path |
355 res += c + path |
330 index = pathlen - 1 |
356 index = pathlen - 1 |
331 elif c == b'%': # variable |
357 elif c == b'%': # variable |
332 path = path[index + 1:] |
358 path = path[index + 1 :] |
333 pathlen = len(path) |
359 pathlen = len(path) |
334 try: |
360 try: |
335 index = path.index(b'%') |
361 index = path.index(b'%') |
336 except ValueError: |
362 except ValueError: |
337 res += b'%' + path |
363 res += b'%' + path |
338 index = pathlen - 1 |
364 index = pathlen - 1 |
339 else: |
365 else: |
340 var = path[:index] |
366 var = path[:index] |
341 res += b'%' + var + b'%' |
367 res += b'%' + var + b'%' |
342 elif c == b'$': # variable |
368 elif c == b'$': # variable |
343 if path[index + 1:index + 2] == b'{': |
369 if path[index + 1 : index + 2] == b'{': |
344 path = path[index + 2:] |
370 path = path[index + 2 :] |
345 pathlen = len(path) |
371 pathlen = len(path) |
346 try: |
372 try: |
347 index = path.index(b'}') |
373 index = path.index(b'}') |
348 var = path[:index] |
374 var = path[:index] |
349 |
375 |
356 res += b'${' + path |
382 res += b'${' + path |
357 index = pathlen - 1 |
383 index = pathlen - 1 |
358 else: |
384 else: |
359 var = b'' |
385 var = b'' |
360 index += 1 |
386 index += 1 |
361 c = path[index:index + 1] |
387 c = path[index : index + 1] |
362 while c != b'' and c in varchars: |
388 while c != b'' and c in varchars: |
363 var += c |
389 var += c |
364 index += 1 |
390 index += 1 |
365 c = path[index:index + 1] |
391 c = path[index : index + 1] |
366 # Some variables (like HG_OLDNODE) may be defined, but have an |
392 # Some variables (like HG_OLDNODE) may be defined, but have an |
367 # empty value. Those need to be skipped because when spawning |
393 # empty value. Those need to be skipped because when spawning |
368 # cmd.exe to run the hook, it doesn't replace %VAR% for an empty |
394 # cmd.exe to run the hook, it doesn't replace %VAR% for an empty |
369 # VAR, and that really confuses things like revset expressions. |
395 # VAR, and that really confuses things like revset expressions. |
370 # OTOH, if it's left in Unix format and the hook runs sh.exe, it |
396 # OTOH, if it's left in Unix format and the hook runs sh.exe, it |
374 else: |
400 else: |
375 res += b'$' + var |
401 res += b'$' + var |
376 |
402 |
377 if c != b'': |
403 if c != b'': |
378 index -= 1 |
404 index -= 1 |
379 elif (c == b'~' and index + 1 < pathlen |
405 elif ( |
380 and path[index + 1:index + 2] in (b'\\', b'/')): |
406 c == b'~' |
|
407 and index + 1 < pathlen |
|
408 and path[index + 1 : index + 2] in (b'\\', b'/') |
|
409 ): |
381 res += "%USERPROFILE%" |
410 res += "%USERPROFILE%" |
382 elif (c == b'\\' and index + 1 < pathlen |
411 elif ( |
383 and path[index + 1:index + 2] in (b'$', b'~')): |
412 c == b'\\' |
|
413 and index + 1 < pathlen |
|
414 and path[index + 1 : index + 2] in (b'$', b'~') |
|
415 ): |
384 # Skip '\', but only if it is escaping $ or ~ |
416 # Skip '\', but only if it is escaping $ or ~ |
385 res += path[index + 1:index + 2] |
417 res += path[index + 1 : index + 2] |
386 index += 1 |
418 index += 1 |
387 else: |
419 else: |
388 res += c |
420 res += c |
389 |
421 |
390 index += 1 |
422 index += 1 |
391 return res |
423 return res |
|
424 |
392 |
425 |
393 # A sequence of backslashes is special iff it precedes a double quote: |
426 # A sequence of backslashes is special iff it precedes a double quote: |
394 # - if there's an even number of backslashes, the double quote is not |
427 # - if there's an even number of backslashes, the double quote is not |
395 # quoted (i.e. it ends the quoted region) |
428 # quoted (i.e. it ends the quoted region) |
396 # - if there's an odd number of backslashes, the double quote is quoted |
429 # - if there's an odd number of backslashes, the double quote is quoted |
430 if s and not _needsshellquote(s) and not _quotere.search(s): |
465 if s and not _needsshellquote(s) and not _quotere.search(s): |
431 # "s" shouldn't have to be quoted |
466 # "s" shouldn't have to be quoted |
432 return s |
467 return s |
433 return b'"%s"' % _quotere.sub(br'\1\1\\\2', s) |
468 return b'"%s"' % _quotere.sub(br'\1\1\\\2', s) |
434 |
469 |
|
470 |
435 def _unquote(s): |
471 def _unquote(s): |
436 if s.startswith(b'"') and s.endswith(b'"'): |
472 if s.startswith(b'"') and s.endswith(b'"'): |
437 return s[1:-1] |
473 return s[1:-1] |
438 return s |
474 return s |
439 |
475 |
|
476 |
440 def shellsplit(s): |
477 def shellsplit(s): |
441 """Parse a command string in cmd.exe way (best-effort)""" |
478 """Parse a command string in cmd.exe way (best-effort)""" |
442 return pycompat.maplist(_unquote, pycompat.shlexsplit(s, posix=False)) |
479 return pycompat.maplist(_unquote, pycompat.shlexsplit(s, posix=False)) |
|
480 |
443 |
481 |
444 def quotecommand(cmd): |
482 def quotecommand(cmd): |
445 """Build a command string suitable for os.popen* calls.""" |
483 """Build a command string suitable for os.popen* calls.""" |
446 if sys.version_info < (2, 7, 1): |
484 if sys.version_info < (2, 7, 1): |
447 # Python versions since 2.7.1 do this extra quoting themselves |
485 # Python versions since 2.7.1 do this extra quoting themselves |
448 return '"' + cmd + '"' |
486 return '"' + cmd + '"' |
449 return cmd |
487 return cmd |
450 |
488 |
|
489 |
451 # if you change this stub into a real check, please try to implement the |
490 # if you change this stub into a real check, please try to implement the |
452 # username and groupname functions above, too. |
491 # username and groupname functions above, too. |
453 def isowner(st): |
492 def isowner(st): |
454 return True |
493 return True |
|
494 |
455 |
495 |
456 def findexe(command): |
496 def findexe(command): |
457 '''Find executable for command searching like cmd.exe does. |
497 '''Find executable for command searching like cmd.exe does. |
458 If command is a basename then PATH is searched for command. |
498 If command is a basename then PATH is searched for command. |
459 PATH isn't searched if command is an absolute or relative path. |
499 PATH isn't searched if command is an absolute or relative path. |
479 executable = findexisting(os.path.join(path, command)) |
519 executable = findexisting(os.path.join(path, command)) |
480 if executable is not None: |
520 if executable is not None: |
481 return executable |
521 return executable |
482 return findexisting(os.path.expanduser(os.path.expandvars(command))) |
522 return findexisting(os.path.expanduser(os.path.expandvars(command))) |
483 |
523 |
|
524 |
484 _wantedkinds = {stat.S_IFREG, stat.S_IFLNK} |
525 _wantedkinds = {stat.S_IFREG, stat.S_IFLNK} |
|
526 |
485 |
527 |
486 def statfiles(files): |
528 def statfiles(files): |
487 '''Stat each file in files. Yield each stat, or None if a file |
529 '''Stat each file in files. Yield each stat, or None if a file |
488 does not exist or has a type we don't care about. |
530 does not exist or has a type we don't care about. |
489 |
531 |
490 Cluster and cache stat per directory to minimize number of OS stat calls.''' |
532 Cluster and cache stat per directory to minimize number of OS stat calls.''' |
491 dircache = {} # dirname -> filename -> status | None if file does not exist |
533 dircache = {} # dirname -> filename -> status | None if file does not exist |
492 getkind = stat.S_IFMT |
534 getkind = stat.S_IFMT |
493 for nf in files: |
535 for nf in files: |
494 nf = normcase(nf) |
536 nf = normcase(nf) |
495 dir, base = os.path.split(nf) |
537 dir, base = os.path.split(nf) |
496 if not dir: |
538 if not dir: |
497 dir = '.' |
539 dir = '.' |
498 cache = dircache.get(dir, None) |
540 cache = dircache.get(dir, None) |
499 if cache is None: |
541 if cache is None: |
500 try: |
542 try: |
501 dmap = dict([(normcase(n), s) |
543 dmap = dict( |
502 for n, k, s in listdir(dir, True) |
544 [ |
503 if getkind(s.st_mode) in _wantedkinds]) |
545 (normcase(n), s) |
|
546 for n, k, s in listdir(dir, True) |
|
547 if getkind(s.st_mode) in _wantedkinds |
|
548 ] |
|
549 ) |
504 except OSError as err: |
550 except OSError as err: |
505 # Python >= 2.5 returns ENOENT and adds winerror field |
551 # Python >= 2.5 returns ENOENT and adds winerror field |
506 # EINVAL is raised if dir is not a directory. |
552 # EINVAL is raised if dir is not a directory. |
507 if err.errno not in (errno.ENOENT, errno.EINVAL, |
553 if err.errno not in (errno.ENOENT, errno.EINVAL, errno.ENOTDIR): |
508 errno.ENOTDIR): |
|
509 raise |
554 raise |
510 dmap = {} |
555 dmap = {} |
511 cache = dircache.setdefault(dir, dmap) |
556 cache = dircache.setdefault(dir, dmap) |
512 yield cache.get(base, None) |
557 yield cache.get(base, None) |
513 |
558 |
|
559 |
514 def username(uid=None): |
560 def username(uid=None): |
515 """Return the name of the user with the given uid. |
561 """Return the name of the user with the given uid. |
516 |
562 |
517 If uid is None, return the name of the current user.""" |
563 If uid is None, return the name of the current user.""" |
518 return None |
564 return None |
519 |
565 |
|
566 |
520 def groupname(gid=None): |
567 def groupname(gid=None): |
521 """Return the name of the group with the given gid. |
568 """Return the name of the group with the given gid. |
522 |
569 |
523 If gid is None, return the name of the current group.""" |
570 If gid is None, return the name of the current group.""" |
524 return None |
571 return None |
525 |
572 |
|
573 |
526 def readlink(pathname): |
574 def readlink(pathname): |
527 return pycompat.fsencode(os.readlink(pycompat.fsdecode(pathname))) |
575 return pycompat.fsencode(os.readlink(pycompat.fsdecode(pathname))) |
|
576 |
528 |
577 |
529 def removedirs(name): |
578 def removedirs(name): |
530 """special version of os.removedirs that does not remove symlinked |
579 """special version of os.removedirs that does not remove symlinked |
531 directories or junction points if they actually contain files""" |
580 directories or junction points if they actually contain files""" |
532 if listdir(name): |
581 if listdir(name): |
542 os.rmdir(head) |
591 os.rmdir(head) |
543 except (ValueError, OSError): |
592 except (ValueError, OSError): |
544 break |
593 break |
545 head, tail = os.path.split(head) |
594 head, tail = os.path.split(head) |
546 |
595 |
|
596 |
547 def rename(src, dst): |
597 def rename(src, dst): |
548 '''atomically rename file src to dst, replacing dst if it exists''' |
598 '''atomically rename file src to dst, replacing dst if it exists''' |
549 try: |
599 try: |
550 os.rename(src, dst) |
600 os.rename(src, dst) |
551 except OSError as e: |
601 except OSError as e: |
552 if e.errno != errno.EEXIST: |
602 if e.errno != errno.EEXIST: |
553 raise |
603 raise |
554 unlink(dst) |
604 unlink(dst) |
555 os.rename(src, dst) |
605 os.rename(src, dst) |
556 |
606 |
|
607 |
557 def gethgcmd(): |
608 def gethgcmd(): |
558 return [encoding.strtolocal(arg) for arg in [sys.executable] + sys.argv[:1]] |
609 return [encoding.strtolocal(arg) for arg in [sys.executable] + sys.argv[:1]] |
|
610 |
559 |
611 |
560 def groupmembers(name): |
612 def groupmembers(name): |
561 # Don't support groups on Windows for now |
613 # Don't support groups on Windows for now |
562 raise KeyError |
614 raise KeyError |
563 |
615 |
|
616 |
564 def isexec(f): |
617 def isexec(f): |
565 return False |
618 return False |
|
619 |
566 |
620 |
567 class cachestat(object): |
621 class cachestat(object): |
568 def __init__(self, path): |
622 def __init__(self, path): |
569 pass |
623 pass |
570 |
624 |
571 def cacheable(self): |
625 def cacheable(self): |
572 return False |
626 return False |
|
627 |
573 |
628 |
574 def lookupreg(key, valname=None, scope=None): |
629 def lookupreg(key, valname=None, scope=None): |
575 ''' Look up a key/value name in the Windows registry. |
630 ''' Look up a key/value name in the Windows registry. |
576 |
631 |
577 valname: value name. If unspecified, the default value for the key |
632 valname: value name. If unspecified, the default value for the key |