diff options
Diffstat (limited to 'git_config.py')
-rw-r--r-- | git_config.py | 156 |
1 files changed, 2 insertions, 154 deletions
diff --git a/git_config.py b/git_config.py index fcd0446c..1d8d1363 100644 --- a/git_config.py +++ b/git_config.py | |||
@@ -18,25 +18,17 @@ from http.client import HTTPException | |||
18 | import json | 18 | import json |
19 | import os | 19 | import os |
20 | import re | 20 | import re |
21 | import signal | ||
22 | import ssl | 21 | import ssl |
23 | import subprocess | 22 | import subprocess |
24 | import sys | 23 | import sys |
25 | try: | ||
26 | import threading as _threading | ||
27 | except ImportError: | ||
28 | import dummy_threading as _threading | ||
29 | import time | ||
30 | import urllib.error | 24 | import urllib.error |
31 | import urllib.request | 25 | import urllib.request |
32 | 26 | ||
33 | from error import GitError, UploadError | 27 | from error import GitError, UploadError |
34 | import platform_utils | 28 | import platform_utils |
35 | from repo_trace import Trace | 29 | from repo_trace import Trace |
36 | 30 | import ssh | |
37 | from git_command import GitCommand | 31 | from git_command import GitCommand |
38 | from git_command import ssh_sock | ||
39 | from git_command import terminate_ssh_clients | ||
40 | from git_refs import R_CHANGES, R_HEADS, R_TAGS | 32 | from git_refs import R_CHANGES, R_HEADS, R_TAGS |
41 | 33 | ||
42 | ID_RE = re.compile(r'^[0-9a-f]{40}$') | 34 | ID_RE = re.compile(r'^[0-9a-f]{40}$') |
@@ -440,129 +432,6 @@ class RefSpec(object): | |||
440 | return s | 432 | return s |
441 | 433 | ||
442 | 434 | ||
443 | _master_processes = [] | ||
444 | _master_keys = set() | ||
445 | _ssh_master = True | ||
446 | _master_keys_lock = None | ||
447 | |||
448 | |||
449 | def init_ssh(): | ||
450 | """Should be called once at the start of repo to init ssh master handling. | ||
451 | |||
452 | At the moment, all we do is to create our lock. | ||
453 | """ | ||
454 | global _master_keys_lock | ||
455 | assert _master_keys_lock is None, "Should only call init_ssh once" | ||
456 | _master_keys_lock = _threading.Lock() | ||
457 | |||
458 | |||
459 | def _open_ssh(host, port=None): | ||
460 | global _ssh_master | ||
461 | |||
462 | # Bail before grabbing the lock if we already know that we aren't going to | ||
463 | # try creating new masters below. | ||
464 | if sys.platform in ('win32', 'cygwin'): | ||
465 | return False | ||
466 | |||
467 | # Acquire the lock. This is needed to prevent opening multiple masters for | ||
468 | # the same host when we're running "repo sync -jN" (for N > 1) _and_ the | ||
469 | # manifest <remote fetch="ssh://xyz"> specifies a different host from the | ||
470 | # one that was passed to repo init. | ||
471 | _master_keys_lock.acquire() | ||
472 | try: | ||
473 | |||
474 | # Check to see whether we already think that the master is running; if we | ||
475 | # think it's already running, return right away. | ||
476 | if port is not None: | ||
477 | key = '%s:%s' % (host, port) | ||
478 | else: | ||
479 | key = host | ||
480 | |||
481 | if key in _master_keys: | ||
482 | return True | ||
483 | |||
484 | if not _ssh_master or 'GIT_SSH' in os.environ: | ||
485 | # Failed earlier, so don't retry. | ||
486 | return False | ||
487 | |||
488 | # We will make two calls to ssh; this is the common part of both calls. | ||
489 | command_base = ['ssh', | ||
490 | '-o', 'ControlPath %s' % ssh_sock(), | ||
491 | host] | ||
492 | if port is not None: | ||
493 | command_base[1:1] = ['-p', str(port)] | ||
494 | |||
495 | # Since the key wasn't in _master_keys, we think that master isn't running. | ||
496 | # ...but before actually starting a master, we'll double-check. This can | ||
497 | # be important because we can't tell that that 'git@myhost.com' is the same | ||
498 | # as 'myhost.com' where "User git" is setup in the user's ~/.ssh/config file. | ||
499 | check_command = command_base + ['-O', 'check'] | ||
500 | try: | ||
501 | Trace(': %s', ' '.join(check_command)) | ||
502 | check_process = subprocess.Popen(check_command, | ||
503 | stdout=subprocess.PIPE, | ||
504 | stderr=subprocess.PIPE) | ||
505 | check_process.communicate() # read output, but ignore it... | ||
506 | isnt_running = check_process.wait() | ||
507 | |||
508 | if not isnt_running: | ||
509 | # Our double-check found that the master _was_ infact running. Add to | ||
510 | # the list of keys. | ||
511 | _master_keys.add(key) | ||
512 | return True | ||
513 | except Exception: | ||
514 | # Ignore excpetions. We we will fall back to the normal command and print | ||
515 | # to the log there. | ||
516 | pass | ||
517 | |||
518 | command = command_base[:1] + ['-M', '-N'] + command_base[1:] | ||
519 | try: | ||
520 | Trace(': %s', ' '.join(command)) | ||
521 | p = subprocess.Popen(command) | ||
522 | except Exception as e: | ||
523 | _ssh_master = False | ||
524 | print('\nwarn: cannot enable ssh control master for %s:%s\n%s' | ||
525 | % (host, port, str(e)), file=sys.stderr) | ||
526 | return False | ||
527 | |||
528 | time.sleep(1) | ||
529 | ssh_died = (p.poll() is not None) | ||
530 | if ssh_died: | ||
531 | return False | ||
532 | |||
533 | _master_processes.append(p) | ||
534 | _master_keys.add(key) | ||
535 | return True | ||
536 | finally: | ||
537 | _master_keys_lock.release() | ||
538 | |||
539 | |||
540 | def close_ssh(): | ||
541 | global _master_keys_lock | ||
542 | |||
543 | terminate_ssh_clients() | ||
544 | |||
545 | for p in _master_processes: | ||
546 | try: | ||
547 | os.kill(p.pid, signal.SIGTERM) | ||
548 | p.wait() | ||
549 | except OSError: | ||
550 | pass | ||
551 | del _master_processes[:] | ||
552 | _master_keys.clear() | ||
553 | |||
554 | d = ssh_sock(create=False) | ||
555 | if d: | ||
556 | try: | ||
557 | platform_utils.rmdir(os.path.dirname(d)) | ||
558 | except OSError: | ||
559 | pass | ||
560 | |||
561 | # We're done with the lock, so we can delete it. | ||
562 | _master_keys_lock = None | ||
563 | |||
564 | |||
565 | URI_SCP = re.compile(r'^([^@:]*@?[^:/]{1,}):') | ||
566 | URI_ALL = re.compile(r'^([a-z][a-z+-]*)://([^@/]*@?[^/]*)/') | 435 | URI_ALL = re.compile(r'^([a-z][a-z+-]*)://([^@/]*@?[^/]*)/') |
567 | 436 | ||
568 | 437 | ||
@@ -614,27 +483,6 @@ def GetUrlCookieFile(url, quiet): | |||
614 | yield cookiefile, None | 483 | yield cookiefile, None |
615 | 484 | ||
616 | 485 | ||
617 | def _preconnect(url): | ||
618 | m = URI_ALL.match(url) | ||
619 | if m: | ||
620 | scheme = m.group(1) | ||
621 | host = m.group(2) | ||
622 | if ':' in host: | ||
623 | host, port = host.split(':') | ||
624 | else: | ||
625 | port = None | ||
626 | if scheme in ('ssh', 'git+ssh', 'ssh+git'): | ||
627 | return _open_ssh(host, port) | ||
628 | return False | ||
629 | |||
630 | m = URI_SCP.match(url) | ||
631 | if m: | ||
632 | host = m.group(1) | ||
633 | return _open_ssh(host) | ||
634 | |||
635 | return False | ||
636 | |||
637 | |||
638 | class Remote(object): | 486 | class Remote(object): |
639 | """Configuration options related to a remote. | 487 | """Configuration options related to a remote. |
640 | """ | 488 | """ |
@@ -673,7 +521,7 @@ class Remote(object): | |||
673 | 521 | ||
674 | def PreConnectFetch(self): | 522 | def PreConnectFetch(self): |
675 | connectionUrl = self._InsteadOf() | 523 | connectionUrl = self._InsteadOf() |
676 | return _preconnect(connectionUrl) | 524 | return ssh.preconnect(connectionUrl) |
677 | 525 | ||
678 | def ReviewUrl(self, userEmail, validate_certs): | 526 | def ReviewUrl(self, userEmail, validate_certs): |
679 | if self._review_url is None: | 527 | if self._review_url is None: |