def synctree(src, dst, onexist=None):
    """Recursively sync files at directory src to dst

    This is more or less equivalent to::

       cp -n -R ${src}/ ${dst}/

    If a file at the same path exists in src and dst, it is NOT overwritten
    in dst. Pass ``onexist`` in order to raise an error on such conditions.

    Args:
        src (path-like): source directory
        dst (path-like): destination directory, does not need to exist
        onexist (callable): function to call if file exists at destination,
            takes the full path to destination file as only argument
    """
    src = pathlib.Path(src).resolve()
    dst = pathlib.Path(dst).resolve()

    if not src.is_dir():
        raise ValueError

    if dst.exists() and not dst.is_dir():
        raise ValueError

    if onexist is None:
        def onexist(): pass

    _synctree(src, dst, onexist)
def synctree ( src , dst , onexist = None ) : src = pathlib . Path ( src ) . resolve ( ) dst = pathlib . Path ( dst ) . resolve ( ) if not src . is_dir ( ) : raise ValueError if dst . exists ( ) and not dst . is_dir ( ) : raise ValueError if onexist is None : def onexist ( ) : pass _synctree ( src , dst , onexist )
Recursively sync files at directory src to dst

    This is more or less equivalent to::

       cp -n -R ${src}/ ${dst}/

    If a file at the same path exists in src and dst, it is NOT overwritten
    in dst. Pass ``onexist`` in order to raise an error on such conditions.

    Args:
        src (path-like): source directory
        dst (path-like): destination directory, does not need to exist
        onexist (callable): function to call if file exists at destination,
            takes the full path to destination file as only argument