Esempio n. 1
0
    def sync(self, source, destination):
        """Synchronise two locations."""
        start_time = time.time()
        self.source = normalise_url(source)
        self.destination = normalise_url(destination)

        # Instantiate the transports.
        try:
            self.source_transport = self.transports[url_split(
                self.source).scheme]()
        except KeyError:
            log.error("Protocol not supported: %s." %
                      url_split(self.source).scheme)
            return
        try:
            self.destination_transport = self.transports[url_split(
                self.destination).scheme]()
        except KeyError:
            log.error("Protocol not supported: %s." %
                      url_split(self.destination).scheme)
            return

        # Give the transports a chance to connect to their servers.
        try:
            self.source_transport.connect(self.source, self.config)
        except:
            log.error("Connection to source failed, exiting...")
            self.exit(1)
        try:
            self.destination_transport.connect(self.destination, self.config)
        except:
            log.error("Connection to destination failed, exiting...")
            self.exit(1)

        # These are the most attributes we can expect from getattr calls in these two protocols.
        self.max_attributes = (self.source_transport.getattr_attributes
                               & self.destination_transport.getattr_attributes)

        self.max_evaluation_attributes = (
            self.source_transport.evaluation_attributes
            & self.destination_transport.evaluation_attributes)

        if not self.check_locations():
            self.exit(1)

        # Begin the actual synchronisation.
        self.recurse()

        self.source_transport.disconnect()
        self.destination_transport.disconnect()
        total_time = time.time() - start_time
        locale.setlocale(locale.LC_NUMERIC, '')
        try:
            bps = locale.format("%d", int(self.bytes_total / total_time), True)
        except ZeroDivisionError:
            bps = "inf"
        log.info("Copied %s files (%s bytes) in %s sec (%s Bps)." %
                 (locale.format("%d", self.file_counter, True),
                  locale.format("%d", self.bytes_total, True),
                  locale.format("%.2f", total_time, True), bps))
Esempio n. 2
0
    def recurse(self):
        """Recursively synchronise everything."""
        source_dir_list = self.source_transport.listdir(self.source)
        dest = FileObject(self.destination_transport, self.destination)
        # If the source is a file, rather than a directory, just copy it. We know for sure that
        # it exists from the checks we did before, so the "False" return value can't be because
        # of that.
        if not source_dir_list:
            # If the destination ends in a slash or is an actual directory:
            if self.destination.endswith("/") or dest.isdir:
                if not dest.isdir:
                    self.destination_transport.mkdir(dest.url)
                # Splice the source filename onto the destination URL.
                dest_url = url_split(dest.url)
                dest_url.file = url_split(self.source,
                                          uses_hostname=self.source_transport.uses_hostname,
                                          split_filename=True).file
                dest_url = url_join(dest_url)
            else:
                dest_url = self.destination
            self.compare_and_copy(
                FileObject(self.source_transport, self.source, {"isdir": False}),
                FileObject(self.destination_transport, dest_url, {"isdir": False}),
                )
            return

        # If source is a directory...
        directory_stack = [FileObject(self.source_transport, self.source, {"isdir": True})]

        # Depth-first tree traversal.
        while directory_stack:
            # TODO: Rethink the assumption that a file cannot have the same name as a directory.
            item = directory_stack.pop()
            log.debug("URL %s is %sa directory." % \
                          (item.url, not item.isdir and "not " or ""))
            if item.isdir:
                # Don't skip the first directory.
                if not self.config.recursive and item.url != self.source:
                    log.info("Skipping directory %s..." % item)
                    continue
                # Obtain a directory list.
                new_dir_list = []
                for new_file in reversed(self.source_transport.listdir(item.url)):
                    if self.include_file(new_file):
                        new_dir_list.append(new_file)
                    else:
                        log.debug("Skipping %s..." % (new_file))
                dest = url_splice(self.source, item.url, self.destination)
                dest = FileObject(self.destination_transport, dest)
                log.debug("Comparing directories %s and %s..." % (item.url, dest.url))
                self.compare_directories(item, new_dir_list, dest.url)
                directory_stack.extend(new_dir_list)
            else:
                dest_url = url_splice(self.source, item.url, self.destination)
                log.debug("Destination URL is %s." % dest_url)
                dest = FileObject(self.destination_transport, dest_url)
                self.compare_and_copy(item, dest)
Esempio n. 3
0
    def sync(self, source, destination):
        """Synchronise two locations."""
        start_time = time.time()
        self.source = normalise_url(source)
        self.destination = normalise_url(destination)

        # Instantiate the transports.
        try:
            self.source_transport = self.transports[url_split(self.source).scheme]()
        except KeyError:
            log.error("Protocol not supported: %s." % url_split(self.source).scheme)
            return
        try:
            self.destination_transport = self.transports[url_split(self.destination).scheme]()
        except KeyError:
            log.error("Protocol not supported: %s." % url_split(self.destination).scheme)
            return

        # Give the transports a chance to connect to their servers.
        try:
            self.source_transport.connect(self.source, self.config)
        except:
            log.error("Connection to source failed, exiting...")
            self.exit(1)
        try:
            self.destination_transport.connect(self.destination, self.config)
        except:
            log.error("Connection to destination failed, exiting...")
            self.exit(1)

        # These are the most attributes we can expect from getattr calls in these two protocols.
        self.max_attributes = (self.source_transport.getattr_attributes &
                               self.destination_transport.getattr_attributes)

        self.max_evaluation_attributes = (self.source_transport.evaluation_attributes &
                                          self.destination_transport.evaluation_attributes)

        if not self.check_locations():
            self.exit(1)

        # Begin the actual synchronisation.
        self.recurse()

        self.source_transport.disconnect()
        self.destination_transport.disconnect()
        total_time = time.time() - start_time
        locale.setlocale(locale.LC_NUMERIC, '')
        try:
            bps = locale.format("%d", int(self.bytes_total / total_time), True)
        except ZeroDivisionError:
            bps = "inf"
        log.info("Copied %s files (%s bytes) in %s sec (%s Bps)." % (
                      locale.format("%d", self.file_counter, True),
                      locale.format("%d", self.bytes_total, True),
                      locale.format("%.2f", total_time, True),
                      bps))
Esempio n. 4
0
    def check_locations(self):
        """Check that the two locations are suitable for synchronisation."""
        if url_split(self.source).get_dict().keys == ["scheme"]:
            log.error(
                "You need to specify something more than that for the source.")
            return False
        elif url_split(self.source).get_dict().keys == ["scheme"]:
            log.error(
                "You need to specify more information than that for the destination."
            )
            return False
        elif not self.source_transport.exists(self.source):
            log.error("The source location \"%s\" does not exist, aborting." %
                      self.source)
            return False

        # Check if both locations are of the same type.
        source_isdir = self.source_transport.isdir(self.source)
        leave = False
        if self.source.startswith(self.destination) and source_isdir:
            log.error(
                "The destination directory is a parent of the source directory."
            )
            leave = True
        elif not hasattr(self.source_transport, "read"):
            log.error("The source protocol is write-only.")
            leave = True
        elif not hasattr(self.destination_transport, "write"):
            log.error("The destination protocol is read-only.")
            leave = True
        elif not hasattr(self.destination_transport,
                         "remove") and self.config.delete:
            log.error(
                "The destination protocol does not support file deletion.")
            leave = True
        elif self.config.requested_attributes - self.source_transport.getattr_attributes:
            log.error("Requested attributes cannot be read: %s." %
                          ", ".join(x for x in self.config.requested_attributes - \
                                    self.source_transport.getattr_attributes)
                          )
            leave = True
        elif self.config.requested_attributes - self.destination_transport.setattr_attributes:
            log.error("Requested attributes cannot be set: %s." %
                          ", ".join(x for x in self.config.requested_attributes - \
                                    self.destination_transport.setattr_attributes)
                          )
            leave = True

        if leave:
            return False
        else:
            return True
Esempio n. 5
0
 def connect(self, url, config):
     """Initiate a connection to the remote host."""
     options = config.full_options
     
     # Make the import global.
     global paramiko
     try:
         # We import paramiko only when we need it because its import is really slow.
         import paramiko
     except ImportError:
         print "SFTP: You will need to install the paramiko library to have sftp support."
         raise
     url = urlfunctions.url_split(url)
     if not url.port:
         url.port = 22
     self._transport = paramiko.Transport((url.hostname, url.port))
     
     username = url.username
     if not url.username:
         if hasattr(options, "username"):
             username = options.username
         else:
             url.username = getpass.getuser()
     
     password = url.password
     if not url.password:
         if hasattr(options, "password"):
             password = options.password
         else:
             password = getpass.getpass(
                 "SFTP: Please enter the password for %s@%s:" % (url.username, url.hostname)
             )
     self._transport.connect(username=username, password=password)
     self._connection = paramiko.SFTPClient.from_transport(self._transport)
Esempio n. 6
0
 def _get_filename(self, url):
     """Retrieve the local filename from a given URL."""
     split_url = urlfunctions.url_split(url, uses_hostname=self.uses_hostname)
     # paths are relative unless they start with two //
     path = split_url.path
     if len(path) > 1 and path.startswith("/"):
         path = path[1:]
     return path
Esempio n. 7
0
    def check_locations(self):
        """Check that the two locations are suitable for synchronisation."""
        if url_split(self.source).get_dict().keys == ["scheme"]:
            log.error("You need to specify something more than that for the source.")
            return False
        elif url_split(self.source).get_dict().keys == ["scheme"]:
            log.error("You need to specify more information than that for the destination.")
            return False
        elif not self.source_transport.exists(self.source):
            log.error("The source location \"%s\" does not exist, aborting." %
                          self.source)
            return False

        # Check if both locations are of the same type.
        source_isdir = self.source_transport.isdir(self.source)
        leave = False
        if self.source.startswith(self.destination) and source_isdir:
            log.error("The destination directory is a parent of the source directory.")
            leave = True
        elif not hasattr(self.source_transport, "read"):
            log.error("The source protocol is write-only.")
            leave = True
        elif not hasattr(self.destination_transport, "write"):
            log.error("The destination protocol is read-only.")
            leave = True
        elif not hasattr(self.destination_transport, "remove") and self.config.delete:
            log.error("The destination protocol does not support file deletion.")
            leave = True
        elif self.config.requested_attributes - self.source_transport.getattr_attributes:
            log.error("Requested attributes cannot be read: %s." %
                          ", ".join(x for x in self.config.requested_attributes - \
                                    self.source_transport.getattr_attributes)
                          )
            leave = True
        elif self.config.requested_attributes - self.destination_transport.setattr_attributes:
            log.error("Requested attributes cannot be set: %s." %
                          ", ".join(x for x in self.config.requested_attributes - \
                                    self.destination_transport.setattr_attributes)
                          )
            leave = True

        if leave:
            return False
        else:
            return True
Esempio n. 8
0
 def _get_filename(self, url, remove_slash=True):
     """Retrieve the local filename from a given URL."""
     # Remove the trailing slash as a convention unless specified otherwise.
     if remove_slash:
         urlfunctions.append_slash(url, False)
     filename = urlfunctions.url_split(url).path
     if filename == "":
         filename = "/"
     return filename
Esempio n. 9
0
 def _get_filename(self, url, remove_slash=True):
     """Retrieve the local filename from a given URL."""
     # Remove the trailing slash as a convention unless specified otherwise.
     if remove_slash:
         urlfunctions.append_slash(url, False)
     filename = urlfunctions.url_split(url).path
     if filename == "":
         filename = "/"
     return filename
Esempio n. 10
0
 def connect(self, url, config):
     """Unpickle the filesystem dictionary."""
     self._storage = urlfunctions.url_split(url).hostname
     # If the storage is in-memory only, don't do anything.
     if self._storage == "memory":
         return
     try:
         pickled_file = open(self._storage, "rb")
     except IOError:
         return
     self._filesystem = pickle.load(pickled_file)
     pickled_file.close()
Esempio n. 11
0
 def connect(self, url, config):
     """Unpickle the filesystem dictionary."""
     self._storage = urlfunctions.url_split(url).hostname
     # If the storage is in-memory only, don't do anything.
     if self._storage == "memory":
         return
     try:
         pickled_file = open(self._storage, "rb")
     except IOError:
         return
     self._filesystem = pickle.load(pickled_file)
     pickled_file.close()
Esempio n. 12
0
 def connect(self, url, config):
     """Initiate a connection to the remote host."""
     options = config.full_options
     
     # Make the import global.
     global paramiko
     try:
         # We import paramiko only when we need it because its import is really slow.
         import paramiko
     except ImportError:
         print "SFTP: You will need to install the paramiko library to have sftp support."
         raise
     url = urlfunctions.url_split(url)
     if not url.port:
         url.port = 22
     self._transport = paramiko.Transport((url.hostname, url.port))
     
     topts = dict()
     
     topts['username'] = url.username
     if not url.username:
         if hasattr(options, "username"):
             topts['username'] = options.username
         else:
             topts['username'] = getpass.getuser()
 
     if hasattr(options, "sshkey"):
         keyfilename = options.sshkey
         
         keydata = open(keyfilename).read()
         
         if "BEGIN DSA" in keydata or "BEGIN DSS" in keydata:
             topts['pkey'] = paramiko.dsskey.DSSKey.from_private_key(StringIO(keydata))
         elif "BEGIN RSA" in keydata:
             topts['pkey'] = paramiko.rsakey.RSAKey.from_private_key(StringIO(keydata))
         else:
             raise BadAuthenticationInformation("Key type in file %s cannot be identified" % (keyfilename))
     else:
         password = url.password
         if not url.password:
             if hasattr(options, "password"):
                 topts['password'] = options.password
             else:
                 topts['password'] = getpass.getpass(
                     "SFTP: Please enter the password for %s@%s:" % (url.username, url.hostname)
                 )
                 
     self._transport.connect(**topts)
     self._connection = paramiko.SFTPClient.from_transport(self._transport)
Esempio n. 13
0
 def test_url_join(self):
     """Test url_join."""
     tests = (
         ("http://*****:*****@myhost:80/some/path/file;things?myhost=hi#lala", True, True),
         ("http://*****:*****@myhost:80/some/path/;things?myhost=hi#lala", True, True),
         ("http://user@myhost/file;things?myhost=hi#lala", True, True),
         ("http://myhost/;things?myhost=hi#lala", True, True),
         ("http://*****:*****@myhost:80/?myhost=hi#lala", True, True),
         ("myhost/", True, True),
         ("user:pass@myhost:80/", True, True),
         ("user:pass@myhost/some#lala", True, True),
         ("http://myhost:80/;things?myhost=hi#lala", True, True),
         ("http://myhost/#lala", True, True),
         ("file://path", False, True),
         ("file://path/file", False, True),
         ("file:///path", False, True),
         ("file:///path/file", False, True),
         ("file:///path/file?something=else", False, True),
     )
     for test in tests:
         self.assertEqual(urlfunctions.url_join(urlfunctions.url_split(*test)), test[0])
Esempio n. 14
0
 def test_url_join(self):
     """Test url_join."""
     tests = (
         ("http://*****:*****@myhost:80/some/path/file;things?myhost=hi#lala",
          True, True),
         ("http://*****:*****@myhost:80/some/path/;things?myhost=hi#lala",
          True, True),
         ("http://user@myhost/file;things?myhost=hi#lala", True, True),
         ("http://myhost/;things?myhost=hi#lala", True, True),
         ("http://*****:*****@myhost:80/?myhost=hi#lala", True, True),
         ("myhost/", True, True),
         ("user:pass@myhost:80/", True, True),
         ("user:pass@myhost/some#lala", True, True),
         ("http://myhost:80/;things?myhost=hi#lala", True, True),
         ("http://myhost/#lala", True, True),
         ("file://path", False, True),
         ("file://path/file", False, True),
         ("file:///path", False, True),
         ("file:///path/file", False, True),
         ("file:///path/file?something=else", False, True),
     )
     for test in tests:
         self.assertEqual(
             urlfunctions.url_join(urlfunctions.url_split(*test)), test[0])
Esempio n. 15
0
 def _get_filename(self, url):
     """Retrieve the local filename from a given URL."""
     split_url = urlfunctions.url_split(url, uses_hostname=self.uses_hostname)
     return split_url.path
Esempio n. 16
0
    def recurse(self):
        """Recursively synchronise everything."""
        source_dir_list = self.source_transport.listdir(self.source)
        dest = FileObject(self.destination_transport, self.destination)
        # If the source is a file, rather than a directory, just copy it. We know for sure that
        # it exists from the checks we did before, so the "False" return value can't be because
        # of that.
        if not source_dir_list:
            # If the destination ends in a slash or is an actual directory:
            if self.destination.endswith("/") or dest.isdir:
                if not dest.isdir:
                    self.destination_transport.mkdir(dest.url)
                # Splice the source filename onto the destination URL.
                dest_url = url_split(dest.url)
                dest_url.file = url_split(
                    self.source,
                    uses_hostname=self.source_transport.uses_hostname,
                    split_filename=True).file
                dest_url = url_join(dest_url)
            else:
                dest_url = self.destination
            self.compare_and_copy(
                FileObject(self.source_transport, self.source,
                           {"isdir": False}),
                FileObject(self.destination_transport, dest_url,
                           {"isdir": False}),
            )
            return

        # If source is a directory...
        directory_stack = [
            FileObject(self.source_transport, self.source, {"isdir": True})
        ]

        # Depth-first tree traversal.
        while directory_stack:
            # TODO: Rethink the assumption that a file cannot have the same name as a directory.
            item = directory_stack.pop()
            log.debug("URL %s is %sa directory." % \
                          (item.url, not item.isdir and "not " or ""))
            if item.isdir:
                # Don't skip the first directory.
                if not self.config.recursive and item.url != self.source:
                    log.info("Skipping directory %s..." % item)
                    continue
                # Obtain a directory list.
                new_dir_list = []
                for new_file in reversed(
                        self.source_transport.listdir(item.url)):
                    if self.include_file(new_file):
                        new_dir_list.append(new_file)
                    else:
                        log.debug("Skipping %s..." % (new_file))
                dest = url_splice(self.source, item.url, self.destination)
                dest = FileObject(self.destination_transport, dest)
                log.debug("Comparing directories %s and %s..." %
                          (item.url, dest.url))
                self.compare_directories(item, new_dir_list, dest.url)
                directory_stack.extend(new_dir_list)
            else:
                dest_url = url_splice(self.source, item.url, self.destination)
                log.debug("Destination URL is %s." % dest_url)
                dest = FileObject(self.destination_transport, dest_url)
                self.compare_and_copy(item, dest)
Esempio n. 17
0
    def compare_directories(self, source, source_dir_list, dest_dir_url):
        """Compare the source's directory list with the destination's and perform any actions
           necessary, such as deleting files or creating directories."""
        dest_dir_list = self.destination_transport.listdir(dest_dir_url)
        if not dest_dir_list:
            if not self.config.dry_run:
                self.destination_transport.mkdir(dest_dir_url)
                # Populate the item's attributes for the remote directory so we can set them.
                attribute_set = self.max_evaluation_attributes & \
                                self.destination_transport.setattr_attributes
                attribute_set = attribute_set | self.config.requested_attributes
                attribute_set = attribute_set ^ self.config.exclude_attributes
                source.populate_attributes(attribute_set)

                self.set_destination_attributes(dest_dir_url,
                                                source.attributes)
            dest_dir_list = []
        # Construct a dictionary of {filename: FileObject} items.
        dest_paths = dict([(url_split(append_slash(x.url, False),
                                      self.destination_transport.uses_hostname,
                                      True).file, x) for x in dest_dir_list])
        create_dirs = []
        for item in source_dir_list:
            # Remove slashes so the splitter can get the filename.
            url = url_split(append_slash(item.url, False),
                            self.source_transport.uses_hostname, True).file
            # If the file exists and both the source and destination are of the same type...
            if url in dest_paths and dest_paths[url].isdir == item.isdir:
                # ...if it's a directory, set its attributes as well...
                if dest_paths[url].isdir:
                    log.info("Setting attributes for %s..." % url)
                    item.populate_attributes(
                        self.max_evaluation_attributes
                        | self.config.requested_attributes)
                    self.set_destination_attributes(dest_paths[url].url,
                                                    item.attributes)
                # ...and remove it from the list.
                del dest_paths[url]
            else:
                # If an item is in the source but not the destination tree...
                if item.isdir and self.config.recursive:
                    # ...create it if it's a directory.
                    create_dirs.append(item)

        if self.config.delete:
            for item in dest_paths.values():
                if item.isdir:
                    if self.config.recursive:
                        log.info("Deleting destination directory %s..." % item)
                        self.recursively_delete(item)
                else:
                    log.info("Deleting destination file %s..." % item)
                    self.destination_transport.remove(item.url)

        if self.config.dry_run:
            return

        # Create directories after we've deleted everything else because sometimes a directory in
        # the source might have the same name as a file, so we need to delete files first.
        for item in create_dirs:
            dest_url = url_splice(self.source, item.url, self.destination)
            self.destination_transport.mkdir(dest_url)
            item.populate_attributes(self.max_evaluation_attributes
                                     | self.config.requested_attributes)
            self.set_destination_attributes(dest_url, item.attributes)
Esempio n. 18
0
 def test_url_split(self):
     """Test url_split."""
     tests = (
         (("http://*****:*****@myhost:80/some/path/file;things?myhost=hi#lala",
           True, False), {
               "scheme": "http",
               "netloc": "user:pass@myhost:80",
               "username": "******",
               "password": "******",
               "hostname": "myhost",
               "port": 80,
               "path": "/some/path/file",
               "file": "",
               "params": "things",
               "query": "myhost=hi",
               "anchor": "lala"
           }),
         (("http://myhost/some/path/file;things?myhost=hi#lala", True,
           False), {
               "scheme": "http",
               "netloc": "myhost",
               "username": "",
               "password": "",
               "hostname": "myhost",
               "port": 0,
               "path": "/some/path/file",
               "file": "",
               "params": "things",
               "query": "myhost=hi",
               "anchor": "lala"
           }),
         (("http://user@myhost/some/path/", True, False), {
             "scheme": "http",
             "netloc": "user@myhost",
             "username": "******",
             "password": "",
             "hostname": "myhost",
             "port": 0,
             "path": "/some/path/",
             "file": "",
             "params": "",
             "query": "",
             "anchor": ""
         }),
         (("http://myhost", True, False), {
             "scheme": "http",
             "netloc": "myhost",
             "username": "",
             "password": "",
             "hostname": "myhost",
             "port": 0,
             "path": "",
             "file": "",
             "params": "",
             "query": "",
             "anchor": ""
         }),
         (("file://some/directory", False, False), {
             "scheme": "file",
             "path": "some/directory",
             "file": "",
             "params": "",
             "query": "",
             "anchor": ""
         }),
         (("file://some/directory", True, True), {
             "scheme": "file",
             "netloc": "some",
             "username": "",
             "password": "",
             "hostname": "some",
             "port": 0,
             "path": "/",
             "file": "directory",
             "params": "",
             "query": "",
             "anchor": ""
         }),
         (("host", True, True), {
             "scheme": "",
             "netloc": "host",
             "username": "",
             "password": "",
             "hostname": "host",
             "port": 0,
             "path": "",
             "file": "",
             "params": "",
             "query": "",
             "anchor": ""
         }),
         (("http://*****:*****@myhost:80/some/path/file;things?arg=hi#lala",
           True, True), {
               "scheme": "http",
               "netloc": "user:pass@myhost:80",
               "username": "******",
               "password": "******",
               "hostname": "myhost",
               "port": 80,
               "path": "/some/path/",
               "file": "file",
               "params": "things",
               "query": "arg=hi",
               "anchor": "lala"
           }),
         (("http://*****:*****@myhost:80/some/path/file#lala", True, False), {
             "scheme": "http",
             "netloc": "user:pass@myhost:80",
             "username": "******",
             "password": "******",
             "hostname": "myhost",
             "port": 80,
             "path": "/some/path/file",
             "file": "",
             "params": "",
             "query": "",
             "anchor": "lala"
         }),
         (("file://I:/some/path/file", False, True), {
             "scheme": "file",
             "path": "I:/some/path/",
             "file": "file",
             "params": "",
             "query": "",
             "anchor": ""
         }),
         (("file://file", False, True), {
             "scheme": "file",
             "path": "",
             "file": "file",
             "params": "",
             "query": "",
             "anchor": ""
         }),
     )
     for test, expected_output in tests:
         result = urlfunctions.url_split(*test)
         for key in expected_output.keys():
             self.assertEqual(getattr(result, key), expected_output[key])
Esempio n. 19
0
    def compare_directories(self, source, source_dir_list, dest_dir_url):
        """Compare the source's directory list with the destination's and perform any actions
           necessary, such as deleting files or creating directories."""
        dest_dir_list = self.destination_transport.listdir(dest_dir_url)
        if not dest_dir_list:
            if not self.config.dry_run:
                self.destination_transport.mkdir(dest_dir_url)
                # Populate the item's attributes for the remote directory so we can set them.
                attribute_set = self.max_evaluation_attributes & \
                                self.destination_transport.setattr_attributes
                attribute_set = attribute_set | self.config.requested_attributes
                attribute_set = attribute_set ^ self.config.exclude_attributes
                source.populate_attributes(attribute_set)

                self.set_destination_attributes(dest_dir_url, source.attributes)
            dest_dir_list = []
        # Construct a dictionary of {filename: FileObject} items.
        dest_paths = dict([(url_split(append_slash(x.url, False),
                                      self.destination_transport.uses_hostname,
                                      True).file, x) for x in dest_dir_list])
        create_dirs = []
        for item in source_dir_list:
            # Remove slashes so the splitter can get the filename.
            url = url_split(append_slash(item.url, False),
                            self.source_transport.uses_hostname,
                            True).file
            # If the file exists and both the source and destination are of the same type...
            if url in dest_paths and dest_paths[url].isdir == item.isdir:
                # ...if it's a directory, set its attributes as well...
                if dest_paths[url].isdir:
                    log.info("Setting attributes for %s..." % url)
                    item.populate_attributes(self.max_evaluation_attributes |
                                             self.config.requested_attributes)
                    self.set_destination_attributes(dest_paths[url].url, item.attributes)
                # ...and remove it from the list.
                del dest_paths[url]
            else:
                # If an item is in the source but not the destination tree...
                if item.isdir and self.config.recursive:
                    # ...create it if it's a directory.
                    create_dirs.append(item)

        if self.config.delete:
            for item in dest_paths.values():
                if item.isdir:
                    if self.config.recursive:
                        log.info("Deleting destination directory %s..." % item)
                        self.recursively_delete(item)
                else:
                    log.info("Deleting destination file %s..." % item)
                    self.destination_transport.remove(item.url)

        if self.config.dry_run:
            return

        # Create directories after we've deleted everything else because sometimes a directory in
        # the source might have the same name as a file, so we need to delete files first.
        for item in create_dirs:
            dest_url = url_splice(self.source, item.url, self.destination)
            self.destination_transport.mkdir(dest_url)
            item.populate_attributes(self.max_evaluation_attributes |
                                       self.config.requested_attributes)
            self.set_destination_attributes(dest_url, item.attributes)
Esempio n. 20
0
 def _get_filename(self, url):
     """Retrieve the local filename from a given URL."""
     split_url = urlfunctions.url_split(url, uses_hostname=self.uses_hostname)
     return split_url.path
Esempio n. 21
0
 def test_url_split(self):
     """Test url_split."""
     tests = (
         (("http://*****:*****@myhost:80/some/path/file;things?myhost=hi#lala", True, False),
          {"scheme": "http",
           "netloc": "user:pass@myhost:80",
           "username": "******",
           "password": "******",
           "hostname": "myhost",
           "port": 80,
           "path": "/some/path/file",
           "file": "",
           "params": "things",
           "query": "myhost=hi",
           "anchor": "lala"}),
         (("http://myhost/some/path/file;things?myhost=hi#lala", True, False),
          {"scheme": "http",
           "netloc": "myhost",
           "username": "",
           "password": "",
           "hostname": "myhost",
           "port": 0,
           "path": "/some/path/file",
           "file": "",
           "params": "things",
           "query": "myhost=hi",
           "anchor": "lala"}),
         (("http://user@myhost/some/path/", True, False),
          {"scheme": "http",
           "netloc": "user@myhost",
           "username": "******",
           "password": "",
           "hostname": "myhost",
           "port": 0,
           "path": "/some/path/",
           "file": "",
           "params": "",
           "query": "",
           "anchor": ""}),
         (("http://myhost", True, False),
          {"scheme": "http",
           "netloc": "myhost",
           "username": "",
           "password": "",
           "hostname": "myhost",
           "port": 0,
           "path": "",
           "file": "",
           "params": "",
           "query": "",
           "anchor": ""}),
         (("file://some/directory", False, False),
          {"scheme": "file",
           "path": "some/directory",
           "file": "",
           "params": "",
           "query": "",
           "anchor": ""}),
         (("file://some/directory", True, True),
          {"scheme": "file",
           "netloc": "some",
           "username": "",
           "password": "",
           "hostname": "some",
           "port": 0,
           "path": "/",
           "file": "directory",
           "params": "",
           "query": "",
           "anchor": ""}),
         (("host", True, True),
          {"scheme": "",
           "netloc": "host",
           "username": "",
           "password": "",
           "hostname": "host",
           "port": 0,
           "path": "",
           "file": "",
           "params": "",
           "query": "",
           "anchor": ""}),
         (("http://*****:*****@myhost:80/some/path/file;things?arg=hi#lala", True, True),
          {"scheme": "http",
           "netloc": "user:pass@myhost:80",
           "username": "******",
           "password": "******",
           "hostname": "myhost",
           "port": 80,
           "path": "/some/path/",
           "file": "file",
           "params": "things",
           "query": "arg=hi",
           "anchor": "lala"}),
         (("http://*****:*****@myhost:80/some/path/file#lala", True, False),
          {"scheme": "http",
           "netloc": "user:pass@myhost:80",
           "username": "******",
           "password": "******",
           "hostname": "myhost",
           "port": 80,
           "path": "/some/path/file",
           "file": "",
           "params": "",
           "query": "",
           "anchor": "lala"}),
         (("file://I:/some/path/file", False, True),
          {"scheme": "file",
           "path": "I:/some/path/",
           "file": "file",
           "params": "",
           "query": "",
           "anchor": ""}),
         (("file://file", False, True),
          {"scheme": "file",
           "path": "",
           "file": "file",
           "params": "",
           "query": "",
           "anchor": ""}),
     )
     for test, expected_output in tests:
         result = urlfunctions.url_split(*test)
         for key in expected_output.keys():
             self.assertEqual(getattr(result, key), expected_output[key])