remote and local file diff
This commit is contained in:
parent
0090a67c41
commit
e399f2e9f9
Binary file not shown.
Binary file not shown.
@ -43,7 +43,7 @@ def recursive_diff_snap(last_tree, current_tree, path='./', bres={}):
|
||||
item = {
|
||||
'name' : key_added,
|
||||
'path' : '%s' % (path,),
|
||||
'type' : 'dir' if isinstance(current_tree[key_added], dict) else 'file',
|
||||
'type' : 'd' if isinstance(current_tree[key_added], dict) else 'f',
|
||||
'hash' : current_tree[key_added],
|
||||
}
|
||||
added.append(item)
|
||||
@ -51,7 +51,7 @@ def recursive_diff_snap(last_tree, current_tree, path='./', bres={}):
|
||||
for name_last, hsh_last in last_tree.items():
|
||||
hsh_current = current_tree.get(name_last)
|
||||
|
||||
last_type = 'dir' if isinstance(hsh_last, dict) else 'file'
|
||||
last_type = 'd' if isinstance(hsh_last, dict) else 'f'
|
||||
|
||||
item = {
|
||||
'name' : name_last,
|
||||
@ -69,7 +69,7 @@ def recursive_diff_snap(last_tree, current_tree, path='./', bres={}):
|
||||
removed.append(item)
|
||||
continue
|
||||
|
||||
current_type = 'dir' if isinstance(hsh_current, dict) else 'file'
|
||||
current_type = 'd' if isinstance(hsh_current, dict) else 'f'
|
||||
|
||||
if type(hsh_last) != type(hsh_current):
|
||||
print(f'{path}{name_last} changed his type in {current_type}')
|
||||
@ -80,6 +80,7 @@ def recursive_diff_snap(last_tree, current_tree, path='./', bres={}):
|
||||
changed.append(item)
|
||||
continue
|
||||
|
||||
# current node is a file
|
||||
if isinstance(hsh_last, str):
|
||||
if hsh_last != hsh_current:
|
||||
print(f'file {path}{name_last} changed his hash')
|
||||
@ -87,11 +88,12 @@ def recursive_diff_snap(last_tree, current_tree, path='./', bres={}):
|
||||
'last_type' : last_type,
|
||||
'current_type' : current_type,
|
||||
'cur_hash' : hsh_current,
|
||||
'last_hash' : hsh_last,
|
||||
})
|
||||
changed.append(item)
|
||||
continue
|
||||
|
||||
# name is dir
|
||||
# current node is dir
|
||||
if (hsh_last == hsh_current):
|
||||
print(f'file {path}{name_last} subtree unchanged ')
|
||||
continue
|
||||
@ -108,6 +110,8 @@ def diff_snap(last_tree, current_tree, path='./'):
|
||||
res = {}
|
||||
if not path.endswith(os.sep): path = path + os.sep
|
||||
recursive_diff_snap(last_tree, current_tree, path=path, bres=res)
|
||||
# return res
|
||||
## Managing moved files is too difficult - for now skip this step
|
||||
# compute moved could save bandwidth
|
||||
res['moved'] = []
|
||||
for n, r in enumerate(res['removed']):
|
||||
|
@ -6,6 +6,9 @@ from pathlib import Path
|
||||
|
||||
from lib.snapshot.generate import local as _genlocal
|
||||
from lib.snapshot import dump as _dump
|
||||
from lib.snapshot.generate.remote import RHAgent
|
||||
|
||||
from lib.diff import fdiff
|
||||
|
||||
from iface import snap
|
||||
|
||||
@ -23,13 +26,21 @@ class Manager():
|
||||
if not local_path or not remote_path:
|
||||
raise Exception('Please specify a local path and a remote path to sync')
|
||||
self.local_path = self.normalize_path(local_path)
|
||||
self.remote_path = self.normalize_path(remote_path)
|
||||
# self.remote_path = self.normalize_path(remote_path)
|
||||
self.init_remote_params(remote_path)
|
||||
|
||||
# self.check_conf()
|
||||
|
||||
# conf_file = conf_file or DEFAULT_MANAGER_CONF
|
||||
# self.conf = _parse_conf.read_conf(conf_file)
|
||||
|
||||
def init_remote_params(self, remote_path):
|
||||
username, other = remote_path.split('@')
|
||||
hostname, remote_path = other.split(':')
|
||||
self.username = username
|
||||
self.hostname = hostname
|
||||
self.remote_path = self.normalize_path(remote_path)
|
||||
|
||||
def check_init_conf(self):
|
||||
local_path = Path(self.local_path)
|
||||
if not local_path.exists():
|
||||
@ -47,7 +58,7 @@ class Manager():
|
||||
if path.endswith(os.sep): return path
|
||||
return '%s%s' % (path, os.sep)
|
||||
|
||||
def mirror(self, dry_run=True):
|
||||
def mirror(self, dry_run=False):
|
||||
'''
|
||||
do an itial rsync
|
||||
|
||||
@ -62,26 +73,20 @@ class Manager():
|
||||
|
||||
local_path = self.local_path
|
||||
remote_path = self.remote_path
|
||||
|
||||
username = self.username
|
||||
hostname = self.hostname
|
||||
|
||||
dry_run_flag = ''
|
||||
|
||||
if dry_run:
|
||||
dry_run_flag = '--dry-run'
|
||||
dry_run_flag = ' --dry-run'
|
||||
|
||||
cmd = ["rsync"]
|
||||
cmd_str = f'rsync -i -aPu --progress{dry_run_flag} -e ssh {username}@{hostname}:{remote_path} {local_path}'
|
||||
|
||||
cmd.extend(["-i"])
|
||||
cmd.extend(["-aPu"])
|
||||
cmd.extend(["--progress"])
|
||||
cmd.extend(["--delete"])
|
||||
# cmd.extend(["--out-format=\"%i %n%L$ %''b\""])
|
||||
cmd.extend(["-e"])
|
||||
cmd.extend(["ssh"])
|
||||
remote_path = self.remote_path
|
||||
cmd.extend(["%s" % (remote_path,)])
|
||||
local_path = self.local_path
|
||||
cmd.extend(["%s" % (local_path,)])
|
||||
cmd = cmd_str.split(' ')
|
||||
print(f'cmd: {cmd}')
|
||||
|
||||
subprocess.run(cmd)
|
||||
subprocess.run(cmd_str.split(' '))
|
||||
|
||||
def compute_local_hash(self):
|
||||
local_path = self.local_path
|
||||
@ -94,11 +99,31 @@ class Manager():
|
||||
snapshot_dump_path = self.normalize_path(snapshot_dump_path)
|
||||
return snapshot_dump_path
|
||||
|
||||
def dump_local_hash(self, hsh):
|
||||
def get_unmerged_path(self):
|
||||
local_path = self.local_path
|
||||
unmerged_path = '%s%s%s%s' % (local_path, '.masy', os.sep, 'unmerged')
|
||||
unmerged_path = self.normalize_path(unmerged_path)
|
||||
return unmerged_path
|
||||
|
||||
def get_tree_diff_path(self, node):
|
||||
local_path = self.local_path
|
||||
tree_diff_path = '%s%s%s%s' % (local_path, '.masy', os.sep, 'diff')
|
||||
tree_diff_path = self.normalize_path(tree_diff_path)
|
||||
# node_path = node['path']
|
||||
# node_name = node['name']
|
||||
# return tree_diff_path
|
||||
return node['path'].replace('.%s' % (os.sep), tree_diff_path)
|
||||
|
||||
def dump_local_hash(self, hsh=None):
|
||||
# local_path = self.local_path
|
||||
# snapshot_dump_path = '%s%s%s%s' % (local_path, '.masy', os.sep, 'snapshot')
|
||||
if hsh is None:
|
||||
hsh = self.compute_local_hash()
|
||||
snapshot_dump_path = self.get_snapshot_path()
|
||||
os.makedirs(snapshot_dump_path)
|
||||
try:
|
||||
os.makedirs(snapshot_dump_path)
|
||||
except FileExistsError:
|
||||
print(f'{snapshot_dump_path} already exists skip creation')
|
||||
_dump.dump_snapshot(hsh, path=snapshot_dump_path)
|
||||
|
||||
def load_local_hash(self):
|
||||
@ -108,6 +133,20 @@ class Manager():
|
||||
snapshot = _dump.load_snapshot(snapshot_dump_path)
|
||||
return snapshot
|
||||
|
||||
def get_absolute_local_path(self, node):
|
||||
node_path = node['path']
|
||||
node_name = node['name']
|
||||
local_file_path = '%s%s' % (node_path, node_name)
|
||||
local_file_path = local_file_path.replace('.%s' % (os.sep), self.local_path)
|
||||
return local_file_path
|
||||
|
||||
def get_absolute_remote_path(self, node):
|
||||
node_path = node['path']
|
||||
node_name = node['name']
|
||||
remote_file_path = '%s%s' % (node_path, node_name)
|
||||
remote_file_path = remote_file_path.replace('.%s' % (os.sep), self.remote_path)
|
||||
return remote_file_path
|
||||
|
||||
def add_sync_to_list(self):
|
||||
home_dir = os.environ.get('HOME')
|
||||
home_dir = self.normalize_path(home_dir)
|
||||
@ -126,13 +165,156 @@ class Manager():
|
||||
def init_sync(self):
|
||||
self.check_init_conf()
|
||||
self.mirror()
|
||||
## maybe it is better to put all in dump_local_hash
|
||||
local_hash = self.compute_local_hash()
|
||||
self.dump_local_hash(local_hash)
|
||||
self.add_sync_to_list()
|
||||
|
||||
def sync(self):
|
||||
# def init_rh_agent(self):
|
||||
# return RHAgent(self.hostname, self.username)
|
||||
|
||||
def get_agent(self):
|
||||
try:
|
||||
return self.rhagent
|
||||
except: pass
|
||||
self.rhagent = RHAgent(self.hostname, self.username)
|
||||
return self.rhagent
|
||||
|
||||
def get_local_snap_diff(self):
|
||||
last_tree = self.load_local_hash()
|
||||
current_tree = self.compute_local_hash()
|
||||
local_snap_diff = snap.diff_snap(last_tree, current_tree)
|
||||
return local_snap_diff
|
||||
|
||||
def get_remote_snap_diff(self):
|
||||
pass
|
||||
|
||||
def store_unmerged_diff(self, nodes):
|
||||
'''
|
||||
node_path is the relative path
|
||||
'''
|
||||
# path = node['path']
|
||||
# name = node['name']
|
||||
|
||||
unmerged_path = self.get_unmerged_path()
|
||||
# unmerged_path = Path(self.local_path)
|
||||
# if not local_path.exists():
|
||||
try:
|
||||
os.makedirs(unmerged_path)
|
||||
except FileExistsError:
|
||||
print(f'{unmerged_path} already exists skip creation of unmerged')
|
||||
|
||||
## generating tree diff
|
||||
# tree_diff_path = self.get_tree_diff_path()
|
||||
todump = []
|
||||
|
||||
for node in nodes:
|
||||
# node_name = node['name']
|
||||
# node_path = node['path']
|
||||
#
|
||||
# node_local_path = '%s%s%s' % (self.local_path, )
|
||||
node_local_path = self.get_absolute_local_path(node)
|
||||
filea_block_tag = '%s%s (local)' % (node['name'], node['cur_hash'])
|
||||
fileb_block_tag = '%s%s (remote)' % (node['name'], node['remote_hash'])
|
||||
# outfile =
|
||||
rfile_buf = node.pop('remote_file')
|
||||
node_diff_path = self.get_tree_diff_path(node)
|
||||
try:
|
||||
os.makedirs(node_diff_path)
|
||||
except FileExistsError:
|
||||
print(f'{node_diff_path} already exists skip creation')
|
||||
outfile = '%s%s' % (self.normalize_path(node_diff_path), node['name'])
|
||||
fdiff.print_diff(node_local_path, rfile_buf, remove_diff_letters_code=False, outfile=outfile, filea_block_tag=filea_block_tag, fileb_block_tag=fileb_block_tag)
|
||||
todump.append(node)
|
||||
|
||||
_dump.dump_snapshot(todump, path=unmerged_path, dump_file_name='.unmerged.json.gz')
|
||||
|
||||
|
||||
|
||||
def load_unmerged_diff(self):
|
||||
unmerged_path = self.get_unmerged_path()
|
||||
dump_file_name='.unmerged.json.gz'
|
||||
nodes = _dump.load_snapshot(unmerged_path, dump_file_name=dump_file_name)
|
||||
return nodes
|
||||
|
||||
|
||||
#### this part is for generating the diffs tree
|
||||
# agent = self.get_agent()
|
||||
##
|
||||
##
|
||||
# unmerged_localpath = path.replace('.%s' % (os.sep,), unmerged_path)
|
||||
# path = path.replace('.%s' % (os.sep,), self.remote_path)
|
||||
# try:
|
||||
# # creating local path
|
||||
# os.makedirs(unmerged_localpath)
|
||||
# except FileExistsError:
|
||||
# print(f'{unmerged_localpath} already exists skip creation of unmerged')
|
||||
# remote_path = '%s%s' % (path, name)
|
||||
# # print(f'local path where to store: {unmerged_localpath}, remote_path: {remote_path}')
|
||||
# agent.get(remote_path, '%s%s' % (unmerged_localpath, name), lambda a,b: print('remote file saved in {unmerged_path}'))
|
||||
|
||||
def sync(self):
|
||||
'''
|
||||
sync:
|
||||
- calculate local diff
|
||||
- collect necessary action to sync server with this node
|
||||
- do a remote diff and compare with the last version in this node
|
||||
if there are not differencies simply do necessary actions to sync
|
||||
if there is differences put the file diff in a specific folder
|
||||
'''
|
||||
# self.init_rh_agent()
|
||||
# last_tree = self.load_local_hash()
|
||||
# current_tree = self.compute_local_hash()
|
||||
local_snap_diff = self.get_local_snap_diff()
|
||||
# rhagent = self.init_rh_agent()
|
||||
agent = self.get_agent()
|
||||
changes = local_snap_diff.get('changed') or []
|
||||
|
||||
# self.store_unmerged_diff(node)
|
||||
|
||||
unmerged = []
|
||||
|
||||
for node in changes:
|
||||
node_name = node['name']
|
||||
node_path = node['path']
|
||||
node_current_type = node['current_type']
|
||||
node_last_type = node['last_type']
|
||||
node_current_hash = node['cur_hash']
|
||||
node_last_hash = node['last_hash']
|
||||
|
||||
if not (node_current_type == node_last_type):
|
||||
print(f'node {node_name} change type in local tree')
|
||||
if node_last_type == 'f':
|
||||
# remote_file_path = '%s%s' % (node_path, node_name)
|
||||
# remote_file_path = remote_file_path.replace('.%s' % (os.sep), self.remote_path)
|
||||
remote_file_path = self.get_absolute_remote_path(node)
|
||||
rfile_buf, rhash = agent.generate_file_hash_oversftp(remote_file_path, return_also_buffer=True)
|
||||
if node_last_hash == rhash:
|
||||
print(f'You can proceed to push {node_name} file it is not changed from the last version')
|
||||
# local_file_path = '%s%s' % (node_path, node_name)
|
||||
# local_file_path = local_file_path.replace('.%s' % (os.sep), self.local_path)
|
||||
local_file_path = self.get_absolute_local_path(node)
|
||||
agent.put(local_file_path, remote_file_path, lambda x,y: print(f'{local_file_path} copied correctly to remote'))
|
||||
else:
|
||||
print(f'{node_path} file it changed local hash: {node_last_hash}, remote hash {rhash}, you can\'t push it directly')
|
||||
# self.store_unmerged_diff(node)
|
||||
node['remote_hash'] = rhash
|
||||
node['remote_file'] = rfile_buf
|
||||
unmerged.append(node)
|
||||
|
||||
if node_last_type == 'd':
|
||||
# remote_path = '%s%s' % (node_path, node_name)
|
||||
# remote_path = remote_file_path.replace('.%s' % (os.sep), self.remote_path)
|
||||
remote_path = self.get_absolute_local_path(node)
|
||||
rhash = agent.generate_tree_hash_oversftp(remote_path)
|
||||
if node_last_hash == rhash:
|
||||
print(f'You can proceed to push {node_name} folder it is not changed from the last version')
|
||||
else:
|
||||
print(f'{node_name} folder it changed from the last version, you can\'t push it directly')
|
||||
|
||||
# print('Remote hash: %s' % (rhash,))
|
||||
if unmerged:
|
||||
self.store_unmerged_diff(unmerged)
|
||||
# self.generate_tree_diff(unmerged)
|
||||
return local_snap_diff
|
||||
|
||||
|
Binary file not shown.
@ -1,40 +1,67 @@
|
||||
import io
|
||||
|
||||
from pathlib import Path
|
||||
import difflib
|
||||
|
||||
def compute_diff(filea_path, fileb_path):
|
||||
with open(filea_path, 'r') as fa:
|
||||
alines = fa.readlines()
|
||||
with open(fileb_path, 'r') as fb:
|
||||
blines = fb.readlines()
|
||||
def is_buf(f):
|
||||
if isinstance(f, io.BytesIO):
|
||||
return True
|
||||
if isinstance(f, io.StringIO):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_lines(file):
|
||||
if is_buf(file):
|
||||
return file.readlines()
|
||||
with open(file, 'r') as f:
|
||||
lines = f.readlines()
|
||||
return lines
|
||||
|
||||
def compute_diff(filea, fileb):
|
||||
'''
|
||||
file* can be a path or a buffer
|
||||
'''
|
||||
alines = get_lines(filea)
|
||||
blines = get_lines(fileb)
|
||||
|
||||
differ = difflib.Differ()
|
||||
res_diff = list(differ.compare(alines, blines))
|
||||
return res_diff
|
||||
|
||||
def format_diff(filea_path, fileb_path, remove_diff_letters_code=False):
|
||||
def get_file_block_tag(file, file_block_tag):
|
||||
if is_buf(file):
|
||||
assert file_block_tag
|
||||
return file_block_tag
|
||||
if file_block_tag:
|
||||
return file_block_tag
|
||||
## file is a path
|
||||
file_obj = Path(file)
|
||||
file_block_tag = file_obj.name
|
||||
return file_block_tag
|
||||
|
||||
def format_diff(filea, fileb, remove_diff_letters_code=False, filea_block_tag='', fileb_block_tag=''):
|
||||
'''
|
||||
"- " line unique to file1
|
||||
"+ " line unique to file2
|
||||
" " line common to both files
|
||||
"? " line not present in either input file -> to skip it
|
||||
'''
|
||||
filea_obj = Path(filea_path)
|
||||
fileb_obj = Path(fileb_path)
|
||||
|
||||
filea_name = filea_obj.name
|
||||
fileb_name = fileb_obj.name
|
||||
|
||||
filea_group_wrap_tmpl = '<<<<<<< '+ filea_name + '\n%s=======\n'
|
||||
fileb_group_wrap_tmpl = '>>>>>>> ' + fileb_name + '\n%s=======\n'
|
||||
|
||||
|
||||
lines_diff = compute_diff(filea_path, fileb_path)
|
||||
filea_block_tag = get_file_block_tag(filea, filea_block_tag)
|
||||
fileb_block_tag = get_file_block_tag(fileb, fileb_block_tag)
|
||||
|
||||
filea_group_wrap_tmpl = '<<<<<<< '+ filea_block_tag + '\n%s=======\n'
|
||||
fileb_group_wrap_tmpl = '>>>>>>> ' + fileb_block_tag + '\n%s=======\n'
|
||||
|
||||
|
||||
lines_diff = compute_diff(filea, fileb)
|
||||
list_blocks = []
|
||||
|
||||
'''
|
||||
list blocks contains object like this
|
||||
{
|
||||
'block_source' : `filea_name|fileb_name|common`
|
||||
'block_source' : `filea_block_tag|fileb_block_tag|common`
|
||||
'block_lines' : `lines of that block`
|
||||
}
|
||||
'''
|
||||
@ -44,11 +71,11 @@ def format_diff(filea_path, fileb_path, remove_diff_letters_code=False):
|
||||
|
||||
if line.startswith('- '):
|
||||
## line in filea
|
||||
block_source = filea_name
|
||||
block_source = filea_block_tag
|
||||
wrap_tmpl = filea_group_wrap_tmpl
|
||||
elif line.startswith('+ '):
|
||||
## line in fileb
|
||||
block_source = fileb_name
|
||||
block_source = fileb_block_tag
|
||||
wrap_tmpl = fileb_group_wrap_tmpl
|
||||
elif line.startswith('? '):
|
||||
continue
|
||||
@ -84,8 +111,8 @@ def format_diff(filea_path, fileb_path, remove_diff_letters_code=False):
|
||||
|
||||
return list_blocks
|
||||
|
||||
def print_diff(filea_path, fileb_path, remove_diff_letters_code=False, outfile=''):
|
||||
formatted = format_diff(filea_path, fileb_path, remove_diff_letters_code=remove_diff_letters_code)
|
||||
def print_diff(filea_path, fileb_path, remove_diff_letters_code=False, outfile='', filea_block_tag='', fileb_block_tag=''):
|
||||
formatted = format_diff(filea_path, fileb_path, remove_diff_letters_code=remove_diff_letters_code, filea_block_tag=filea_block_tag, fileb_block_tag=fileb_block_tag)
|
||||
|
||||
out_str = ''
|
||||
|
||||
|
Binary file not shown.
BIN
src/lib/sclient/__pycache__/base_agent.cpython-39.pyc
Normal file
BIN
src/lib/sclient/__pycache__/base_agent.cpython-39.pyc
Normal file
Binary file not shown.
@ -1,13 +1,11 @@
|
||||
import stat
|
||||
|
||||
import paramiko
|
||||
import paramiko.sftp_client as _sftp_client
|
||||
from lib.sclient.base_agent import BaseAgent
|
||||
|
||||
HOSTS_KEYS_PATH = '/home/luca/.ssh/known_hosts'
|
||||
PKEY_PATH = '/home/luca/.ssh/notanamber_rsa'
|
||||
# import paramiko.sftp_client as _sftp_client
|
||||
|
||||
HOSTNAME = '107.152.32.78'
|
||||
USERNAME = 'notanamber'
|
||||
# HOSTNAME = '107.152.32.78'
|
||||
# USERNAME = 'notanamber'
|
||||
|
||||
|
||||
'''
|
||||
@ -21,23 +19,16 @@ def downLoadFile(sftp, remotePath, localPath):
|
||||
sftp.get(fileattr.filename, os.path.join(localPath, fileattr.filename))
|
||||
'''
|
||||
|
||||
class SyncAgent():
|
||||
class SyncAgent(BaseAgent):
|
||||
'''
|
||||
it give to you a sftp client for using to compute remote hash
|
||||
and basic ftp command to synchronize local and remote
|
||||
'''
|
||||
|
||||
def __init__(self):
|
||||
self.pkey = paramiko.RSAKey.from_private_key_file(PKEY_PATH)
|
||||
self.client = paramiko.SSHClient()
|
||||
self.client.load_host_keys(filename=HOSTS_KEYS_PATH)
|
||||
def __init__(self, hostname, username):
|
||||
BaseAgent.__init__(self, hostname, username)
|
||||
self.sftpc = None
|
||||
|
||||
def connect(self):
|
||||
'''
|
||||
this method generates the underlying `Trasport`
|
||||
'''
|
||||
self.client.connect(hostname=HOSTNAME, username=USERNAME, pkey=self.pkey, look_for_keys=False)
|
||||
|
||||
def close(self):
|
||||
self.client.close()
|
||||
|
||||
def compute_hash(self, name):
|
||||
self.connect()
|
||||
stdin, stdout, stderr = self.client.exec_command("sha256sum %s | awk '{print $1}'" % (name, ))
|
||||
@ -68,6 +59,26 @@ class SyncAgent():
|
||||
continue
|
||||
print('name: %s is regular FILE' % (attr.filename))
|
||||
|
||||
def put(self, localpath, remotepath, callback=None):
|
||||
'''
|
||||
wrap the method put of paramiko sftp client
|
||||
Copy a local file (localpath) to the SFTP server as remotepath.
|
||||
Any exception raised by operations will be passed through. This method is primarily provided as a convenience.
|
||||
'''
|
||||
sftpc = self.get_sftp_client()
|
||||
sftpc.put(localpath, remotepath, callback=callback)
|
||||
|
||||
synca = SyncAgent()
|
||||
def get(self, localpath, remotepath, callback=None):
|
||||
sftpc = self.get_sftp_client()
|
||||
sftpc.get(localpath, remotepath, callback=callback)
|
||||
|
||||
def open(self, remotepath):
|
||||
sftpc = self.get_sftp_client()
|
||||
buf = ''
|
||||
with sftpc.open(remotepath,mode='r') as rfile:
|
||||
buf = rfile.read()
|
||||
return buf
|
||||
|
||||
|
||||
# synca = SyncAgent()
|
||||
# sftpc = a.get_sftp_client()
|
||||
|
36
src/lib/sclient/base_agent.py
Normal file
36
src/lib/sclient/base_agent.py
Normal file
@ -0,0 +1,36 @@
|
||||
import paramiko
|
||||
from paramiko import SSHConfig
|
||||
|
||||
HOSTS_KEYS_PATH = '/home/luca/.ssh/known_hosts'
|
||||
PKEY_PATH = '/home/luca/.ssh/notanamber_rsa'
|
||||
|
||||
class BaseAgent():
|
||||
'''
|
||||
Basic ssh connection layer
|
||||
'''
|
||||
|
||||
def __init__(self, hostname, username):
|
||||
self.hostname = hostname
|
||||
self.username = username
|
||||
self.pkey = paramiko.RSAKey.from_private_key_file(PKEY_PATH)
|
||||
self.client = paramiko.SSHClient()
|
||||
self.client.load_host_keys(filename=HOSTS_KEYS_PATH)
|
||||
|
||||
def get_hostname_from_sshconfig(self):
|
||||
ssh_config_path = "/home/luca/.ssh/config"
|
||||
ssh_host = self.hostname
|
||||
config = SSHConfig()
|
||||
config_file = open(ssh_config_path)
|
||||
config.parse(config_file)
|
||||
readed = config.lookup(ssh_host)
|
||||
return readed['hostname']
|
||||
|
||||
def connect(self):
|
||||
'''
|
||||
this method generates the underlying `Trasport`
|
||||
'''
|
||||
hostname = self.get_hostname_from_sshconfig()
|
||||
self.client.connect(hostname=hostname, username=self.username, pkey=self.pkey, look_for_keys=False)
|
||||
|
||||
def close(self):
|
||||
self.client.close()
|
Binary file not shown.
Binary file not shown.
@ -35,6 +35,9 @@ def generate_tree_hash(root_path :str):
|
||||
|
||||
items = os.listdir(root_path)
|
||||
for item in items:
|
||||
## exclude folder for the tree
|
||||
if item in ['.masy']:
|
||||
continue
|
||||
absolute_item_path = root_path + item
|
||||
print('absolute_item_path: %s, item %s, isdir: %s' % (absolute_item_path, item, os.path.isdir(absolute_item_path)))
|
||||
if os.path.isdir(absolute_item_path):
|
||||
|
@ -1,129 +1,139 @@
|
||||
import stat
|
||||
import os
|
||||
import hashlib
|
||||
import time
|
||||
import json
|
||||
import io
|
||||
import gzip
|
||||
|
||||
import asyncio
|
||||
import functools
|
||||
|
||||
import time
|
||||
from lib.sclient.agent import SyncAgent
|
||||
|
||||
from lib.sclient import agent as _agent
|
||||
class RHAgent():
|
||||
def __init__(self, hostname, username):
|
||||
## load ssh config and read the ip of hostname
|
||||
self.hostname = hostname
|
||||
self.username = username
|
||||
self.agent = SyncAgent(hostname, username)
|
||||
|
||||
def get_sftp_client():
|
||||
a = self.agent
|
||||
return a.get_sftp_client()
|
||||
|
||||
def generate_rfile_hash(file_path, hexdigest=True, client=None):
|
||||
if not client:
|
||||
a = _agent.synca
|
||||
def generate_rfile_hash(self, file_path, hexdigest=True, return_also_buffer=False):
|
||||
a = self.agent
|
||||
client = a.get_sftp_client()
|
||||
|
||||
with client.open(file_path, "rb") as f:
|
||||
buf = f.read()
|
||||
print(f'Trying to get {file_path}')
|
||||
|
||||
if hexdigest: return hashlib.md5(buf).hexdigest()
|
||||
return hashlib.md5(buf).digest()
|
||||
with client.open(file_path, "rb") as f:
|
||||
buf = f.read()
|
||||
|
||||
# def check_isdir(path: str):
|
||||
# if not os.path.isdir(path):
|
||||
# raise Exception('Provide a valid folder to start the hashing')
|
||||
#
|
||||
# if not path.endswith(os.path.sep):
|
||||
# path = path + os.path.sep
|
||||
# return path
|
||||
|
||||
def generate_tree_hash_oversftp(root_path :str):
|
||||
'''
|
||||
@param root_path string, root_path in remote server
|
||||
generate a map of hashes starting from `root_path` recursively
|
||||
'''
|
||||
# if not os.path.isdir(root_path):
|
||||
# raise Exception('Provide a valid folder to start the hashing')
|
||||
#
|
||||
# if not root_path.endswith(os.path.sep):
|
||||
# root_path = root_path + os.path.sep
|
||||
# root_path = check_isdir(root_path)
|
||||
|
||||
rtreemap = {}
|
||||
|
||||
if not root_path.endswith(os.path.sep):
|
||||
root_path = root_path + os.path.sep
|
||||
|
||||
a = _agent.synca
|
||||
sftpc = a.get_sftp_client()
|
||||
|
||||
for item in sftpc.listdir_attr(root_path):
|
||||
absolute_item_path = root_path + item.filename
|
||||
print('absolute_item_path: %s, item %s, isdir: %s' % (absolute_item_path, item.filename, stat.S_ISDIR(item.st_mode)))
|
||||
if stat.S_ISDIR(item.st_mode):
|
||||
rtreemap[item.filename] = generate_tree_hash_oversftp(absolute_item_path)
|
||||
if hexdigest:
|
||||
dig = hashlib.md5(buf).hexdigest()
|
||||
else:
|
||||
rtreemap[item.filename] = generate_rfile_hash(absolute_item_path, client=sftpc)
|
||||
dig = hashlib.md5(buf).digest()
|
||||
|
||||
return rtreemap
|
||||
if not return_also_buffer:
|
||||
return dig
|
||||
|
||||
async def generate_rfile_hash_async(file_path, hexdigest=True, client=None):
|
||||
if not client:
|
||||
a = _agent.synca
|
||||
return (io.BytesIO(buf), dig)
|
||||
|
||||
def generate_tree_hash_oversftp(self, root_path :str):
|
||||
'''
|
||||
@param root_path string, root_path in remote server
|
||||
generate a map of hashes starting from `root_path` recursively
|
||||
'''
|
||||
|
||||
|
||||
rtreemap = {}
|
||||
|
||||
if not root_path.endswith(os.path.sep):
|
||||
root_path = root_path + os.path.sep
|
||||
|
||||
a = self.agent
|
||||
sftpc = a.get_sftp_client()
|
||||
|
||||
for item in sftpc.listdir_attr(root_path):
|
||||
absolute_item_path = root_path + item.filename
|
||||
print('absolute_item_path: %s, item %s, isdir: %s' % (absolute_item_path, item.filename, stat.S_ISDIR(item.st_mode)))
|
||||
if stat.S_ISDIR(item.st_mode):
|
||||
rtreemap[item.filename] = self.generate_tree_hash_oversftp(absolute_item_path)
|
||||
else:
|
||||
rtreemap[item.filename] = self.generate_rfile_hash(absolute_item_path)
|
||||
|
||||
return rtreemap
|
||||
|
||||
def generate_file_hash_oversftp(self, file_path: str, return_also_buffer: bool=False):
|
||||
a = self.agent
|
||||
sftpc = a.get_sftp_client()
|
||||
return self.generate_rfile_hash(file_path, return_also_buffer=return_also_buffer)
|
||||
|
||||
async def generate_rfile_hash_async(self, file_path, hexdigest=True):
|
||||
a = self.agent
|
||||
client = a.get_sftp_client()
|
||||
|
||||
with client.open(file_path, "rb") as f:
|
||||
buf = f.read()
|
||||
with client.open(file_path, "rb") as f:
|
||||
buf = f.read()
|
||||
|
||||
if hexdigest: return hashlib.md5(buf).hexdigest()
|
||||
return hashlib.md5(buf).digest()
|
||||
if hexdigest: return hashlib.md5(buf).hexdigest()
|
||||
return hashlib.md5(buf).digest()
|
||||
|
||||
async def generate_tree_hash_oversftp_async(root_path :str):
|
||||
'''
|
||||
@param root_path string, root_path in remote server
|
||||
generate a map of hashes starting from `root_path` recursively
|
||||
'''
|
||||
# if not os.path.isdir(root_path):
|
||||
# raise Exception('Provide a valid folder to start the hashing')
|
||||
#
|
||||
# if not root_path.endswith(os.path.sep):
|
||||
# root_path = root_path + os.path.sep
|
||||
# root_path = check_isdir(root_path)
|
||||
async def generate_tree_hash_oversftp_async(self, root_path :str):
|
||||
'''
|
||||
@param root_path string, root_path in remote server
|
||||
generate a map of hashes starting from `root_path` recursively
|
||||
'''
|
||||
# if not os.path.isdir(root_path):
|
||||
# raise Exception('Provide a valid folder to start the hashing')
|
||||
#
|
||||
# if not root_path.endswith(os.path.sep):
|
||||
# root_path = root_path + os.path.sep
|
||||
# root_path = check_isdir(root_path)
|
||||
|
||||
rtreemap = {}
|
||||
rtreemap = {}
|
||||
|
||||
if not root_path.endswith(os.path.sep):
|
||||
root_path = root_path + os.path.sep
|
||||
if not root_path.endswith(os.path.sep):
|
||||
root_path = root_path + os.path.sep
|
||||
|
||||
a = _agent.synca
|
||||
sftpc = a.get_sftp_client()
|
||||
a = self.agent
|
||||
sftpc = a.get_sftp_client()
|
||||
|
||||
def dtask_done_cback(fname, f):
|
||||
print('dtask done %s' % (fname,))
|
||||
rtreemap[fname] = f.result()
|
||||
def dtask_done_cback(fname, f):
|
||||
print('dtask done %s' % (fname,))
|
||||
rtreemap[fname] = f.result()
|
||||
|
||||
def ftask_done_cback(fname, f):
|
||||
print('ftask done %s' % (fname,))
|
||||
rtreemap[fname] = f.result()
|
||||
def ftask_done_cback(fname, f):
|
||||
print('ftask done %s' % (fname,))
|
||||
rtreemap[fname] = f.result()
|
||||
|
||||
# futures_map = {}
|
||||
tasks = []
|
||||
for item in sftpc.listdir_attr(root_path):
|
||||
absolute_item_path = root_path + item.filename
|
||||
print('absolute_item_path: %s, item %s, isdir: %s' % (absolute_item_path, item.filename, stat.S_ISDIR(item.st_mode)))
|
||||
if stat.S_ISDIR(item.st_mode):
|
||||
# rtreemap[item.filename] = await generate_tree_hash_oversftp_async(absolute_item_path)
|
||||
dtask = asyncio.create_task(generate_tree_hash_oversftp_async(absolute_item_path))
|
||||
dtask.add_done_callback(functools.partial(dtask_done_cback, item.filename))
|
||||
tasks.append(dtask)
|
||||
else:
|
||||
# rtreemap[item.filename] = await generate_rfile_hash_async(absolute_item_path, client=sftpc)
|
||||
ftask = asyncio.create_task(generate_rfile_hash_async(absolute_item_path, client=sftpc))
|
||||
ftask.add_done_callback(functools.partial(ftask_done_cback, item.filename))
|
||||
tasks.append(ftask)
|
||||
# item.filename
|
||||
|
||||
await asyncio.gather(*tasks)
|
||||
return rtreemap
|
||||
# futures_map = {}
|
||||
tasks = []
|
||||
for item in sftpc.listdir_attr(root_path):
|
||||
absolute_item_path = root_path + item.filename
|
||||
print('absolute_item_path: %s, item %s, isdir: %s' % (absolute_item_path, item.filename, stat.S_ISDIR(item.st_mode)))
|
||||
if stat.S_ISDIR(item.st_mode):
|
||||
# rtreemap[item.filename] = await generate_tree_hash_oversftp_async(absolute_item_path)
|
||||
dtask = asyncio.create_task(self.generate_tree_hash_oversftp_async(absolute_item_path))
|
||||
dtask.add_done_callback(functools.partial(dtask_done_cback, item.filename))
|
||||
tasks.append(dtask)
|
||||
else:
|
||||
# rtreemap[item.filename] = await generate_rfile_hash_async(absolute_item_path, client=sftpc)
|
||||
ftask = asyncio.create_task(self.generate_rfile_hash_async(absolute_item_path))
|
||||
ftask.add_done_callback(functools.partial(ftask_done_cback, item.filename))
|
||||
tasks.append(ftask)
|
||||
# item.filename
|
||||
|
||||
await asyncio.gather(*tasks)
|
||||
return rtreemap
|
||||
|
||||
def test_sync_rtree(path='/home/notanamber/notes_dev/'):
|
||||
start = time.time()
|
||||
print('Start task')
|
||||
rtree = generate_tree_hash_oversftp(path)
|
||||
rhagent = RHAgent('myvps', 'notanamber')
|
||||
rtree = rhagent.generate_tree_hash_oversftp(path)
|
||||
end = time.time()
|
||||
print('task done in %.2f' % (end - start))
|
||||
return rtree
|
||||
@ -131,35 +141,39 @@ def test_sync_rtree(path='/home/notanamber/notes_dev/'):
|
||||
def test_async_rtree(path='/home/notanamber/notes_dev/'):
|
||||
start = time.time()
|
||||
print('Start task')
|
||||
rtree = asyncio.run(generate_tree_hash_oversftp_async(path))
|
||||
rhagent = RHAgent('myvps', 'notanamber')
|
||||
rtree = asyncio.run(rhagent.generate_tree_hash_oversftp_async(path))
|
||||
end = time.time()
|
||||
print('task done in %.2f' % (end - start))
|
||||
return rtree
|
||||
|
||||
def get_test_agent():
|
||||
rhagent = RHAgent('myvps', 'notanamber')
|
||||
a = rhagent
|
||||
return a
|
||||
|
||||
|
||||
'''
|
||||
a
|
||||
- b
|
||||
- c
|
||||
- k.txt
|
||||
i.txt
|
||||
g.txt
|
||||
j.txt
|
||||
k.txt
|
||||
'''
|
||||
a
|
||||
- b
|
||||
- c
|
||||
- k.txt
|
||||
i.txt
|
||||
g.txt
|
||||
j.txt
|
||||
k.txt
|
||||
|
||||
tree['a'] = {
|
||||
'b' : {
|
||||
tree['a'] = {
|
||||
'b' : {
|
||||
|
||||
},
|
||||
'j.txt' : '012349jasdfh9934',
|
||||
},
|
||||
'j.txt' : '012349jasdfh9934',
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
'''
|
||||
|
||||
'''
|
||||
|
||||
root_path = '/home/luca/rsyn_test_fap'
|
||||
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user