~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/sftp.py

  • Committer: Robert Collins
  • Date: 2006-03-28 14:29:13 UTC
  • mto: (1626.2.1 integration)
  • mto: This revision was merged to the branch mainline in revision 1628.
  • Revision ID: robertc@robertcollins.net-20060328142913-ac5afb37075719c6
Convert log to use the new tsort.merge_sort routine.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Robey Pointer <robey@lag.net>
2
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005 Robey Pointer <robey@lag.net>, Canonical Ltd
3
2
 
4
3
# This program is free software; you can redistribute it and/or modify
5
4
# it under the terms of the GNU General Public License as published by
35
34
                           FileExists, 
36
35
                           TransportNotPossible, NoSuchFile, PathNotChild,
37
36
                           TransportError,
38
 
                           LockError, 
39
 
                           PathError,
40
 
                           ParamikoNotPresent,
 
37
                           LockError, ParamikoNotPresent
41
38
                           )
42
39
from bzrlib.osutils import pathjoin, fancy_rename
43
40
from bzrlib.trace import mutter, warning, error
44
 
from bzrlib.transport import (
45
 
    register_urlparse_netloc_protocol,
46
 
    Server,
47
 
    Transport,
48
 
    urlescape,
49
 
    )
 
41
from bzrlib.transport import Transport, Server, urlescape
50
42
import bzrlib.ui
51
43
 
52
44
try:
61
53
    from paramiko.sftp_file import SFTPFile
62
54
    from paramiko.sftp_client import SFTPClient
63
55
 
64
 
 
65
 
register_urlparse_netloc_protocol('sftp')
66
 
 
67
 
 
68
 
def os_specific_subprocess_params():
69
 
    """Get O/S specific subprocess parameters."""
70
 
    if sys.platform == 'win32':
71
 
        # setting the process group and closing fds is not supported on 
72
 
        # win32
73
 
        return {}
74
 
    else:
75
 
        # we close fds as the child process does not need them to be open.
76
 
        # we set the process group so that signals from the keyboard like
77
 
        # 'SIGINT' - KeyboardInterrupt - are not recieved in the child procecss
78
 
        # if we do not do this, then the sftp/ssh subprocesses will terminate 
79
 
        # when a user hits CTRL-C, and we are unable to use them to unlock the
80
 
        # remote branch/repository etc.
81
 
        return {'preexec_fn': os.setpgrp,
82
 
                'close_fds': True,
83
 
                }
84
 
 
 
56
if 'sftp' not in urlparse.uses_netloc:
 
57
    urlparse.uses_netloc.append('sftp')
85
58
 
86
59
# don't use prefetch unless paramiko version >= 1.5.2 (there were bugs earlier)
87
60
_default_do_prefetch = False
88
 
if getattr(paramiko, '__version_info__', (0, 0, 0)) >= (1, 5, 5):
 
61
if getattr(paramiko, '__version_info__', (0, 0, 0)) >= (1, 5, 2):
89
62
    _default_do_prefetch = True
90
63
 
91
64
 
 
65
_close_fds = True
 
66
if sys.platform == 'win32':
 
67
    # close_fds not supported on win32
 
68
    _close_fds = False
 
69
 
92
70
_ssh_vendor = None
 
71
 
93
72
def _get_ssh_vendor():
94
73
    """Find out what version of SSH is on the system."""
95
74
    global _ssh_vendor
106
85
 
107
86
    try:
108
87
        p = subprocess.Popen(['ssh', '-V'],
 
88
                             close_fds=_close_fds,
109
89
                             stdin=subprocess.PIPE,
110
90
                             stdout=subprocess.PIPE,
111
 
                             stderr=subprocess.PIPE,
112
 
                             **os_specific_subprocess_params())
 
91
                             stderr=subprocess.PIPE)
113
92
        returncode = p.returncode
114
93
        stdout, stderr = p.communicate()
115
94
    except OSError:
154
133
                args.extend(['-l', user])
155
134
            args.extend(['-s', 'sftp', hostname])
156
135
 
157
 
        self.proc = subprocess.Popen(args,
 
136
        self.proc = subprocess.Popen(args, close_fds=_close_fds,
158
137
                                     stdin=subprocess.PIPE,
159
 
                                     stdout=subprocess.PIPE,
160
 
                                     **os_specific_subprocess_params())
 
138
                                     stdout=subprocess.PIPE)
161
139
 
162
140
    def send(self, data):
163
141
        return os.write(self.proc.stdin.fileno(), data)
206
184
# X seconds. But that requires a lot more fanciness.
207
185
_connected_hosts = weakref.WeakValueDictionary()
208
186
 
209
 
def clear_connection_cache():
210
 
    """Remove all hosts from the SFTP connection cache.
211
 
 
212
 
    Primarily useful for test cases wanting to force garbage collection.
213
 
    """
214
 
    _connected_hosts.clear()
215
 
 
216
187
 
217
188
def load_host_keys():
218
189
    """
296
267
        self._parse_url(base)
297
268
        base = self._unparse_url()
298
269
        if base[-1] != '/':
299
 
            base += '/'
 
270
            base = base + '/'
300
271
        super(SFTPTransport, self).__init__(base)
301
272
        if clone_from is None:
302
273
            self._sftp_connect()
493
464
            self._translate_io_exception(e, path, ': unable to mkdir',
494
465
                failure_exc=FileExists)
495
466
 
496
 
    def _translate_io_exception(self, e, path, more_info='', 
497
 
                                failure_exc=PathError):
 
467
    def _translate_io_exception(self, e, path, more_info='', failure_exc=NoSuchFile):
498
468
        """Translate a paramiko or IOError into a friendlier exception.
499
469
 
500
470
        :param e: The original exception
504
474
        :param failure_exc: Paramiko has the super fun ability to raise completely
505
475
                           opaque errors that just set "e.args = ('Failure',)" with
506
476
                           no more information.
507
 
                           If this parameter is set, it defines the exception 
508
 
                           to raise in these cases.
 
477
                           This sometimes means FileExists, but it also sometimes
 
478
                           means NoSuchFile
509
479
        """
510
480
        # paramiko seems to generate detailless errors.
511
481
        self._translate_error(e, path, raise_generic=False)
523
493
            mutter('Raising exception with errno %s', e.errno)
524
494
        raise e
525
495
 
526
 
    def append(self, relpath, f, mode=None):
 
496
    def append(self, relpath, f):
527
497
        """
528
498
        Append the text in the file-like object into the final
529
499
        location.
531
501
        try:
532
502
            path = self._remote_path(relpath)
533
503
            fout = self._sftp.file(path, 'ab')
534
 
            if mode is not None:
535
 
                self._sftp.chmod(path, mode)
536
504
            result = fout.tell()
537
505
            self._pump(f, fout)
538
506
            return result
643
611
            netloc = '%s@%s' % (urllib.quote(self._username), netloc)
644
612
        if self._port is not None:
645
613
            netloc = '%s:%d' % (netloc, self._port)
 
614
 
646
615
        return urlparse.urlunparse(('sftp', netloc, path, '', '', ''))
647
616
 
648
617
    def _split_url(self, url):