163 lines
4.5 KiB
Python
163 lines
4.5 KiB
Python
'''
|
|
A simple pythontool to sync two folders (or harddrives)
|
|
Copyright (C) 2018 Yannis Gerlach aka MrBesen
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as published
|
|
by the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
'''
|
|
import os
|
|
from shutil import copy2
|
|
|
|
sync1 = '/home/yannis/Projects/ownsync/test/s1/'
|
|
sync2 = '/home/yannis/Projects/ownsync/test/s2/'
|
|
dataname = '.sync'
|
|
|
|
def endwithslash(str):
|
|
if str[:-1] == '/':
|
|
return str
|
|
return str + '/'
|
|
|
|
|
|
def readfiletoarray(file):
|
|
try:
|
|
f = open(file, 'r')
|
|
data = f.readlines()
|
|
f.close()
|
|
return data
|
|
except Exception as e:
|
|
print('Error reading sync data', e)
|
|
return []
|
|
|
|
|
|
def shouldsync(fromfile, tofile, dataf, datat):
|
|
if os.path.exists(tofile):
|
|
return getlastchange(tofile) < getlastchange(fromfile) # only if source file is newer
|
|
elif tofile in dataf: # should nver be the case
|
|
return False # file existed once, but was deleted on source
|
|
elif tofile in datat: # file was synced once, but deleted on target.
|
|
return False
|
|
return True # file dont exists and never existed
|
|
|
|
|
|
def getlastchange(file):
|
|
return os.path.getmtime(file)
|
|
|
|
|
|
def scandir(dir):
|
|
data = []
|
|
for file in os.listdir(dir):
|
|
if os.path.isfile(dir + file):
|
|
data.append(dir + file)
|
|
else:
|
|
data.append(dir + file)
|
|
for f in scandir(dir + file + '/'):
|
|
data.append(f)
|
|
return data
|
|
|
|
|
|
def rm(path):
|
|
if os.path.isfile(path):
|
|
os.remove(path)
|
|
else:
|
|
os.rmdir(path)
|
|
|
|
|
|
def updatedata(path):
|
|
data = scandir(path)
|
|
f = open(path + dataname, 'w+')
|
|
for d in data:
|
|
d = d[len(path):]
|
|
if d != dataname:
|
|
f.write(d + '\n')
|
|
f.close()
|
|
|
|
|
|
def syncnew(fro, to):
|
|
#read data
|
|
dataf = readfiletoarray(fro + dataname)
|
|
datat = readfiletoarray(to + dataname)
|
|
print(len(dataf), 'nodes loaded.')
|
|
listffiles = scandir(fro)
|
|
|
|
#remove prefix
|
|
pos = -1
|
|
for i in range(0, len(listffiles)):
|
|
listffiles[i] = listffiles[i][len(fro):]
|
|
if listffiles[i] == dataname: # remove .sync file from list
|
|
pos = i
|
|
|
|
if pos > -1:
|
|
del listffiles[pos]
|
|
|
|
for f in listffiles:
|
|
print('syncing: ', f)
|
|
if (not os.path.isfile(fro + f)) and os.path.exists(fro + f): # TODO: check if folder was deleted at target.
|
|
if not os.path.exists(to + f): # seperate if to not enter elif
|
|
# print('make dir:', to + f)
|
|
#if is folder and exists in from then create folder in to.
|
|
os.makedirs(to + f)
|
|
elif shouldsync(fro + f, to + f, dataf, datat):
|
|
folder = to + f
|
|
folder = folder[:folder.rfind('/')+1]
|
|
# print('make required dir:', folder)
|
|
if not os.path.exists(folder):
|
|
os.makedirs(folder)
|
|
|
|
print(fro + f, '->', to + f)
|
|
copy2(fro + f, to + f)
|
|
else:
|
|
print('skipping', f)
|
|
|
|
# delete files, that were deleted on source
|
|
for f in dataf:
|
|
f = f[:-1] # remove trailing \n
|
|
if not os.path.exists(fro + f):
|
|
print('delete file', to + f)
|
|
# rm(fro + f)
|
|
|
|
|
|
#MAIN
|
|
#setup
|
|
sync1 = endwithslash(sync1)
|
|
sync2 = endwithslash(sync2)
|
|
|
|
sync1ex = True
|
|
if os.path.exists(sync1):
|
|
updatedata(sync1)
|
|
else:
|
|
sync1ex = False
|
|
|
|
sync2ex = True
|
|
if os.path.exists(sync2):
|
|
updatedata(sync2)
|
|
else:
|
|
sync2ex = False
|
|
|
|
if not sync1ex and not sync2ex:
|
|
print('both folders do not exists, exiting.')
|
|
else:
|
|
print('Location A: ', sync1, '\nLocation B: ', sync2)
|
|
if sync1ex:
|
|
print('Sync A -> B')
|
|
syncnew(sync1, sync2)
|
|
print('update changes.')
|
|
updatedata(sync2) # update changes
|
|
print('Done.')
|
|
if sync2ex:
|
|
print('Sync B -> A')
|
|
syncnew(sync2, sync1)
|
|
print('update changes.')
|
|
updatedata(sync1) # update changes
|
|
print('Done.')
|
|
print('Done.')
|