mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 12:54:40 +01:00
216 lines
6.3 KiB
Python
216 lines
6.3 KiB
Python
#!/usr/local/bin/python3
|
|
# https://github.com/snullp/pySync/blob/master/pySync.py
|
|
|
|
import sys
|
|
import shutil
|
|
import os
|
|
import time
|
|
import configparser
|
|
from os.path import (
|
|
getsize,
|
|
getmtime,
|
|
isfile,
|
|
isdir,
|
|
join,
|
|
abspath,
|
|
expanduser,
|
|
realpath
|
|
)
|
|
import logging
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
ignoreFiles = ("Thumbs.db", ".DS_Store")
|
|
|
|
# this feature is not yet implemented
|
|
ignorePaths = []
|
|
|
|
if os.name == 'nt':
|
|
# msvcrt can't function correctly in IDLE
|
|
if 'idlelib.run' in sys.modules:
|
|
print("Please don't run this script in IDLE.")
|
|
sys.exit(0)
|
|
import msvcrt
|
|
|
|
def flush_input(str, set=None):
|
|
if not set:
|
|
while msvcrt.kbhit():
|
|
ch = msvcrt.getch()
|
|
if ch == '\xff':
|
|
print("msvcrt is broken, this is weird.")
|
|
sys.exit(0)
|
|
return input(str)
|
|
else:
|
|
return set
|
|
else:
|
|
import select
|
|
|
|
def flush_input(str, set=None):
|
|
if not set:
|
|
while len(select.select([sys.stdin.fileno()], [], [], 0.0)[0]) > 0:
|
|
os.read(sys.stdin.fileno(), 4096)
|
|
return input(str)
|
|
else:
|
|
return set
|
|
|
|
|
|
def compare(fa, fb, options_input=[]):
|
|
if isfile(fa) == isfile(fb):
|
|
if isdir(fa):
|
|
walktree(fa, fb, options_input)
|
|
elif isfile(fa):
|
|
if getsize(fa) != getsize(fb) \
|
|
or int(getmtime(fa)) != int(getmtime(fb)):
|
|
log.info(str((fa, ': size=', getsize(fa), 'mtime=',
|
|
time.asctime(time.localtime(getmtime(fa))))))
|
|
log.info(str((fb, ': size=', getsize(fb), 'mtime=',
|
|
time.asctime(time.localtime(getmtime(fb))))))
|
|
if getmtime(fa) > getmtime(fb):
|
|
act = '>'
|
|
else:
|
|
act = '<'
|
|
|
|
set = [i for i in options_input if i in [">", "<"]][0]
|
|
|
|
s = flush_input('What to do?(>,<,r,n)[' + act + ']', set=set)
|
|
if len(s) > 0:
|
|
act = s[0]
|
|
if act == '>':
|
|
shutil.copy2(fa, fb)
|
|
elif act == '<':
|
|
shutil.copy2(fb, fa)
|
|
elif act == 'r':
|
|
if isdir(fa):
|
|
shutil.rmtree(fa)
|
|
elif isfile(fa):
|
|
os.remove(fa)
|
|
else:
|
|
log.info(str(('Remove: Skipping', fa)))
|
|
if isdir(fb):
|
|
shutil.rmtree(fb)
|
|
elif isfile(fb):
|
|
os.remove(fb)
|
|
else:
|
|
log.info(str(('Remove: Skipping', fb)))
|
|
|
|
else:
|
|
log.debug(str(('Compare: Skipping non-dir and non-file', fa)))
|
|
else:
|
|
log.error(str(('Error:', fa, ',', fb, 'have different file type')))
|
|
|
|
|
|
def copy(fa, fb, options_input=[]):
|
|
set = [i for i in options_input if i in ["y"]][0]
|
|
s = flush_input('Copy ' + fa + ' to another side?(r,y,n)[y]', set=set)
|
|
if len(s) > 0:
|
|
act = s[0]
|
|
else:
|
|
act = 'y'
|
|
if act == 'y':
|
|
if isdir(fa):
|
|
shutil.copytree(fa, fb)
|
|
elif isfile(fa):
|
|
shutil.copy2(fa, fb)
|
|
else:
|
|
log.debug(str(('Copy: Skipping ', fa)))
|
|
elif act == 'r':
|
|
if isdir(fa):
|
|
shutil.rmtree(fa)
|
|
elif isfile(fa):
|
|
os.remove(fa)
|
|
else:
|
|
log.debug(str(('Remove: Skipping ', fa)))
|
|
|
|
|
|
stoentry = []
|
|
tarentry = []
|
|
|
|
|
|
def walktree(source, target, options_input=[]):
|
|
srclist = os.listdir(source)
|
|
tarlist = os.listdir(target)
|
|
if '!sync' in srclist:
|
|
return
|
|
if '!sync' in tarlist:
|
|
return
|
|
# files in source dir...
|
|
for f in srclist:
|
|
if f in ignoreFiles:
|
|
continue
|
|
spath = join(source, f)
|
|
tpath = join(target, f)
|
|
if spath in ignorePaths:
|
|
continue
|
|
if spath in stoentry:
|
|
# just in case target also have this one
|
|
if f in tarlist:
|
|
del tarlist[tarlist.index(f)]
|
|
continue
|
|
|
|
# if also exists in target dir
|
|
if f in tarlist:
|
|
del tarlist[tarlist.index(f)]
|
|
compare(spath, tpath, options_input)
|
|
|
|
# exists in source dir only
|
|
else:
|
|
copy(spath, tpath, options_input)
|
|
|
|
# exists in target dir only
|
|
set = [i for i in options_input if i in ["<"]]
|
|
|
|
for f in tarlist:
|
|
if f in ignoreFiles:
|
|
continue
|
|
spath = join(source, f)
|
|
tpath = join(target, f)
|
|
if tpath in ignorePaths:
|
|
continue
|
|
if tpath in tarentry:
|
|
continue
|
|
if set:
|
|
copy(tpath, spath, options_input)
|
|
else:
|
|
print("REMOVING: {}".format(f))
|
|
if os.path.isdir(tpath):
|
|
shutil.rmtree(tpath)
|
|
else:
|
|
os.remove(tpath)
|
|
print("REMOVING: {}".format(f))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
stoconf = configparser.RawConfigParser()
|
|
tarconf = configparser.RawConfigParser()
|
|
stoconf.read("pySync.ini")
|
|
tarconf.read(expanduser("~/.pysync"))
|
|
stoname = stoconf.sections()[0]
|
|
tarname = tarconf.sections()[0]
|
|
|
|
# calculate storage's base folder
|
|
if stoconf.has_option(stoname, 'BASE'):
|
|
stobase = abspath(stoconf.get(stoname, 'BASE'))
|
|
stoconf.remove_option(stoname, 'BASE')
|
|
else:
|
|
stobase = os.getcwd()
|
|
|
|
# same, for target's base folder
|
|
if tarconf.has_option(tarname, 'BASE'):
|
|
tarbase = abspath(tarconf.get(tarname, 'BASE'))
|
|
tarconf.remove_option(tarname, 'BASE')
|
|
else:
|
|
tarbase = expanduser('~/')
|
|
|
|
print("Syncing between", stoname, "and", tarname)
|
|
sto_content = {x: realpath(join(stobase, stoconf.get(stoname, x)))
|
|
for x in stoconf.options(stoname)}
|
|
tar_content = {x: realpath(join(tarbase, tarconf.get(tarname, x)))
|
|
for x in tarconf.options(tarname)}
|
|
stoentry = [sto_content[x] for x in sto_content]
|
|
tarentry = [tar_content[x] for x in tar_content]
|
|
|
|
for folder in sto_content:
|
|
if folder in tar_content:
|
|
print('Processing', folder)
|
|
walktree(sto_content[folder], tar_content[folder], options_input)
|
|
print("Done.")
|