~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/sftp.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2006-09-06 16:21:16 UTC
  • mfrom: (1955.3.30 transport_bytes)
  • Revision ID: pqm@pqm.ubuntu.com-20060906162116-90b02cf97bcc11e8
(jam) create Transport.*_{file,bytes}

Show diffs side-by-side

added added

removed removed

Lines of Context:
366
366
            # on to the next
367
367
            cur_coalesced = cur_coalesced_stack.next()
368
368
 
369
 
    def put(self, relpath, f, mode=None):
 
369
    def put_file(self, relpath, f, mode=None):
370
370
        """
371
 
        Copy the file-like or string object into the location.
 
371
        Copy the file-like object into the location.
372
372
 
373
373
        :param relpath: Location to put the contents, relative to base.
374
 
        :param f:       File-like or string object.
 
374
        :param f:       File-like object.
375
375
        :param mode: The final mode for the file
376
376
        """
377
377
        final_path = self._remote_path(relpath)
389
389
                self._pump(f, fout)
390
390
            except (IOError, paramiko.SSHException), e:
391
391
                self._translate_io_exception(e, tmp_abspath)
 
392
            # XXX: This doesn't truly help like we would like it to.
 
393
            #      The problem is that openssh strips sticky bits. So while we
 
394
            #      can properly set group write permission, we lose the group
 
395
            #      sticky bit. So it is probably best to stop chmodding, and
 
396
            #      just tell users that they need to set the umask correctly.
 
397
            #      The attr.st_mode = mode, in _sftp_open_exclusive
 
398
            #      will handle when the user wants the final mode to be more 
 
399
            #      restrictive. And then we avoid a round trip. Unless 
 
400
            #      paramiko decides to expose an async chmod()
 
401
 
 
402
            # This is designed to chmod() right before we close.
 
403
            # Because we set_pipelined() earlier, theoretically we might 
 
404
            # avoid the round trip for fout.close()
392
405
            if mode is not None:
393
406
                self._sftp.chmod(tmp_abspath, mode)
394
407
            fout.close()
412
425
            # raise the original with its traceback if we can.
413
426
            raise
414
427
 
 
428
    def _put_non_atomic_helper(self, relpath, writer, mode=None,
 
429
                               create_parent_dir=False):
 
430
        abspath = self._remote_path(relpath)
 
431
 
 
432
        # TODO: jam 20060816 paramiko doesn't publicly expose a way to
 
433
        #       set the file mode at create time. If it does, use it.
 
434
        #       But for now, we just chmod later anyway.
 
435
 
 
436
        def _open_and_write_file():
 
437
            """Try to open the target file, raise error on failure"""
 
438
            fout = None
 
439
            try:
 
440
                try:
 
441
                    fout = self._sftp.file(abspath, mode='wb')
 
442
                    fout.set_pipelined(True)
 
443
                    writer(fout)
 
444
                except (paramiko.SSHException, IOError), e:
 
445
                    self._translate_io_exception(e, abspath,
 
446
                                                 ': unable to open')
 
447
 
 
448
                # This is designed to chmod() right before we close.
 
449
                # Because we set_pipelined() earlier, theoretically we might 
 
450
                # avoid the round trip for fout.close()
 
451
                if mode is not None:
 
452
                    self._sftp.chmod(abspath, mode)
 
453
            finally:
 
454
                if fout is not None:
 
455
                    fout.close()
 
456
 
 
457
        if not create_parent_dir:
 
458
            _open_and_write_file()
 
459
            return
 
460
 
 
461
        # Try error handling to create the parent directory if we need to
 
462
        try:
 
463
            _open_and_write_file()
 
464
        except NoSuchFile:
 
465
            # Try to create the parent directory, and then go back to
 
466
            # writing the file
 
467
            parent_dir = os.path.dirname(abspath)
 
468
            try:
 
469
                self._sftp.mkdir(parent_dir)
 
470
            except (paramiko.SSHException, IOError), e:
 
471
                self._translate_io_exception(e, abspath, ': unable to open')
 
472
            _open_and_write_file()
 
473
 
 
474
    def put_file_non_atomic(self, relpath, f, mode=None,
 
475
                            create_parent_dir=False):
 
476
        """Copy the file-like object into the target location.
 
477
 
 
478
        This function is not strictly safe to use. It is only meant to
 
479
        be used when you already know that the target does not exist.
 
480
        It is not safe, because it will open and truncate the remote
 
481
        file. So there may be a time when the file has invalid contents.
 
482
 
 
483
        :param relpath: The remote location to put the contents.
 
484
        :param f:       File-like object.
 
485
        :param mode:    Possible access permissions for new file.
 
486
                        None means do not set remote permissions.
 
487
        :param create_parent_dir: If we cannot create the target file because
 
488
                        the parent directory does not exist, go ahead and
 
489
                        create it, and then try again.
 
490
        """
 
491
        def writer(fout):
 
492
            self._pump(f, fout)
 
493
        self._put_non_atomic_helper(relpath, writer, mode=mode,
 
494
                                    create_parent_dir=create_parent_dir)
 
495
 
 
496
    def put_bytes_non_atomic(self, relpath, bytes, mode=None,
 
497
                             create_parent_dir=False):
 
498
        def writer(fout):
 
499
            fout.write(bytes)
 
500
        self._put_non_atomic_helper(relpath, writer, mode=mode,
 
501
                                    create_parent_dir=create_parent_dir)
 
502
 
415
503
    def iter_files_recursive(self):
416
504
        """Walk the relative paths of all files in this transport."""
417
505
        queue = list(self.list_dir('.'))
428
516
        """Create a directory at the given path."""
429
517
        path = self._remote_path(relpath)
430
518
        try:
431
 
            # In the paramiko documentation, it says that passing a mode flag 
432
 
            # will filtered against the server umask.
433
 
            # StubSFTPServer does not do this, which would be nice, because it is
434
 
            # what we really want :)
435
 
            # However, real servers do use umask, so we really should do it that way
436
519
            self._sftp.mkdir(path)
437
520
            if mode is not None:
438
521
                self._sftp.chmod(path, mode=mode)
470
553
            mutter('Raising exception with errno %s', e.errno)
471
554
        raise e
472
555
 
473
 
    def append(self, relpath, f, mode=None):
 
556
    def append_file(self, relpath, f, mode=None):
474
557
        """
475
558
        Append the text in the file-like object into the final
476
559
        location.
641
724
        :param abspath: The remote absolute path where the file should be opened
642
725
        :param mode: The mode permissions bits for the new file
643
726
        """
 
727
        # TODO: jam 20060816 Paramiko >= 1.6.2 (probably earlier) supports
 
728
        #       using the 'x' flag to indicate SFTP_FLAG_EXCL.
 
729
        #       However, there is no way to set the permission mode at open 
 
730
        #       time using the sftp_client.file() functionality.
644
731
        path = self._sftp._adjust_cwd(abspath)
645
732
        # mutter('sftp abspath %s => %s', abspath, path)
646
733
        attr = SFTPAttributes()