87 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			87 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Python
		
	
	
	
 | 
						|
def f():
 | 
						|
    import os, stat, shutil, md5
 | 
						|
    destdir, options = channel.receive() 
 | 
						|
    modifiedfiles = []
 | 
						|
 | 
						|
    def remove(path):
 | 
						|
        assert path.startswith(destdir)
 | 
						|
        try:
 | 
						|
            os.unlink(path)
 | 
						|
        except OSError:
 | 
						|
            # assume it's a dir
 | 
						|
            shutil.rmtree(path)
 | 
						|
 | 
						|
    def receive_directory_structure(path, relcomponents):
 | 
						|
        try:
 | 
						|
            st = os.lstat(path)
 | 
						|
        except OSError:
 | 
						|
            st = None
 | 
						|
        msg = channel.receive()
 | 
						|
        if isinstance(msg, list):
 | 
						|
            if st and not stat.S_ISDIR(st.st_mode):
 | 
						|
                os.unlink(path)
 | 
						|
                st = None
 | 
						|
            if not st:
 | 
						|
                os.makedirs(path)
 | 
						|
            entrynames = {}
 | 
						|
            for entryname in msg:
 | 
						|
                receive_directory_structure(os.path.join(path, entryname),
 | 
						|
                    relcomponents + [entryname])
 | 
						|
                entrynames[entryname] = True
 | 
						|
            if options.get('delete'): 
 | 
						|
                for othername in os.listdir(path):
 | 
						|
                    if othername not in entrynames:
 | 
						|
                        otherpath = os.path.join(path, othername)
 | 
						|
                        remove(otherpath)
 | 
						|
        elif msg is not None:
 | 
						|
            checksum = None
 | 
						|
            if st:
 | 
						|
                if stat.S_ISREG(st.st_mode):
 | 
						|
                    msg_mtime, msg_size = msg
 | 
						|
                    if msg_size != st.st_size:
 | 
						|
                        pass
 | 
						|
                    elif msg_mtime != st.st_mtime:
 | 
						|
                        f = open(path, 'rb')
 | 
						|
                        checksum = md5.md5(f.read()).digest()
 | 
						|
                        f.close()
 | 
						|
                    else:
 | 
						|
                        return    # already fine
 | 
						|
                else:
 | 
						|
                    remove(path)
 | 
						|
            channel.send(("send", (relcomponents, checksum)))
 | 
						|
            modifiedfiles.append((path, msg))
 | 
						|
    receive_directory_structure(destdir, [])
 | 
						|
 | 
						|
    STRICT_CHECK = False    # seems most useful this way for py.test
 | 
						|
    channel.send(("list_done", None))
 | 
						|
 | 
						|
    for path, (time, size) in modifiedfiles:
 | 
						|
        data = channel.receive()
 | 
						|
        channel.send(("ack", path[len(destdir) + 1:]))
 | 
						|
        if data is not None:
 | 
						|
            if STRICT_CHECK and len(data) != size:
 | 
						|
                raise IOError('file modified during rsync: %r' % (path,))
 | 
						|
            f = open(path, 'wb')
 | 
						|
            f.write(data)
 | 
						|
            f.close()
 | 
						|
        os.utime(path, (time, time))
 | 
						|
        del data
 | 
						|
    channel.send(("links", None))
 | 
						|
 | 
						|
    msg = channel.receive()
 | 
						|
    while msg is not 42:
 | 
						|
        # we get symlink
 | 
						|
        _type, relpath, linkpoint = msg
 | 
						|
        assert _type == "link"
 | 
						|
        path = os.path.join(destdir, relpath)
 | 
						|
        try:
 | 
						|
            remove(path)
 | 
						|
        except OSError:
 | 
						|
            pass
 | 
						|
 | 
						|
        os.symlink(os.path.join(destdir, linkpoint), path)
 | 
						|
        msg = channel.receive()
 | 
						|
    channel.send(("done", None))
 | 
						|
 |