ownsync/ownssync.py

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.')