okay. so. let's try this out.

This commit is contained in:
brent s. 2020-07-24 01:37:36 -04:00
parent 803fb7c5fa
commit a2e9075671
Signed by: bts
GPG Key ID: 8C004C2F93481F6B
4 changed files with 90 additions and 32 deletions

View File

@ -9,11 +9,23 @@ _logger = logging.getLogger()
class BaseFetcher(object): class BaseFetcher(object):
type = None type = None


def __init__(self, domain, port, path, dest, owner = None, filechecks = None, *args, **kwargs): def __init__(self,
domain,
port,
path,
dest,
owner = None,
filechecks = None,
mtime = False,
offset = None,
*args,
**kwargs):
self.domain = domain self.domain = domain
self.port = int(port) self.port = int(port)
self.path = path self.path = path
self.dest = os.path.abspath(os.path.expanduser(dest)) self.dest = os.path.abspath(os.path.expanduser(dest))
self.mtime = mtime
self.offset = offset
self.url = '{0}://{1}:{2}/{3}'.format(self.type, self.domain, self.port, self.path.lstrip('/')) self.url = '{0}://{1}:{2}/{3}'.format(self.type, self.domain, self.port, self.path.lstrip('/'))
self.owner = owner self.owner = owner
self.filechecks = filechecks self.filechecks = filechecks
@ -25,15 +37,24 @@ class BaseFetcher(object):
def check(self): def check(self):
for k, v in self.filechecks['remote'].items(): for k, v in self.filechecks['remote'].items():
if v: if v:
tstmp_raw = self.fetch_content(v.path).decode('utf-8').strip() if self.mtime:
if '%s' in v.fmt: self.timestamps[k] = self.fetch_content(v.path, mtime_only = True)
tstmp = datetime.datetime.fromtimestamp(float(tstmp_raw))
else: else:
tstmp = datetime.datetime.strptime(tstmp_raw, v.fmt) tstmp_raw = self.fetch_content(v.path).decode('utf-8').strip()
self.timestamps[k] = tstmp if '%s' in v.fmt:
tstmp = datetime.datetime.fromtimestamp(float(tstmp_raw))
else:
tstmp = datetime.datetime.strptime(tstmp_raw, v.fmt)
self.timestamps[k] = tstmp
if self.offset:
if self.offset.mod == '+' or not self.offset.mod:
newval = self.timestamps[k] + self.offset.offset
elif self.offset.mod == '-':
newval = self.timestamps[k] - self.offset.offset
self.timestamps[k] = newval
_logger.debug('Updated upstream timestamps: {0}'.format(self.timestamps)) _logger.debug('Updated upstream timestamps: {0}'.format(self.timestamps))
return(None) return(None)


def fetch_content(self, path): def fetch_content(self, path, mtime_only = False):
# Dummy func. # Dummy func.
return(b'') return(b'')

View File

@ -1,3 +1,4 @@
import datetime
import ftplib import ftplib
import logging import logging
import io import io
@ -13,8 +14,8 @@ _logger = logging.getLogger()
class FTP(_base.BaseFetcher): class FTP(_base.BaseFetcher):
type = 'ftp' type = 'ftp'


def __init__(self, domain, port, path, dest, owner = None, *args, **kwargs): def __init__(self, domain, port, path, dest, owner = None, mtime = False, offset = None, *args, **kwargs):
super().__init__(domain, port, path, dest, owner = owner, *args, **kwargs) super().__init__(domain, port, path, dest, owner = owner, mtime = mtime, offset = offset, *args, **kwargs)
_logger.debug('Instantiated FTP fetcher') _logger.debug('Instantiated FTP fetcher')
self.handler = ftplib.FTP(self.domain) self.handler = ftplib.FTP(self.domain)
_logger.debug('Configured handler for {0}'.format(self.domain)) _logger.debug('Configured handler for {0}'.format(self.domain))
@ -31,7 +32,7 @@ class FTP(_base.BaseFetcher):


def _disconnect(self): def _disconnect(self):
if self.connected: if self.connected:
self.handler.quit() self.handler.close()
_logger.debug('Disconnected from {0}:{1} as Anonymous'.format(self.domain, self.port)) _logger.debug('Disconnected from {0}:{1} as Anonymous'.format(self.domain, self.port))
self.connected = False self.connected = False
return(None) return(None)
@ -90,13 +91,23 @@ class FTP(_base.BaseFetcher):
self._disconnect() self._disconnect()
return(None) return(None)


def fetch_content(self, remote_filepath): def fetch_content(self, remote_filepath, mtime_only = False):
self._connect() self._connect()
buf = io.BytesIO() if mtime_only:
self.handler.retrbinary('RETR {0}'.format(remote_filepath), buf.write) directory, file = os.path.split(remote_filepath)
parent = '/{0}'.format(directory.lstrip('/'))
meta = self.handler.mlsd(parent)
file_info = dict(meta)[file]
tstmp = file_info['modify']
content = datetime.datetime.strptime(tstmp, '%Y%m%d%H%M%S')
else:
buf = io.BytesIO()
self.handler.retrbinary('RETR {0}'.format(remote_filepath), buf.write)
self._disconnect()
buf.seek(0, 0)
content = buf.read()
self._disconnect() self._disconnect()
buf.seek(0, 0) return(content)
return(buf.read())


def fetch_dir(self, pathspec): def fetch_dir(self, pathspec):
self._connect() self._connect()

View File

@ -1,3 +1,4 @@
import datetime
import logging import logging
import os import os
import subprocess import subprocess
@ -29,9 +30,20 @@ class RSync(_base.BaseFetcher):
owner = None, owner = None,
log = True, log = True,
filechecks = None, filechecks = None,
offset = None,
mtime = False,
*args, *args,
**kwargs): **kwargs):
super().__init__(domain, port, path, dest, owner = owner, filechecks = filechecks, *args, **kwargs) super().__init__(domain,
port,
path,
dest,
owner = owner,
filechecks = filechecks,
offset = offset,
mtime = mtime
*args,
**kwargs)
_logger.debug('Instantiated RSync fetcher') _logger.debug('Instantiated RSync fetcher')
if rsync_args: if rsync_args:
self.rsync_args = rsync_args.args[:] self.rsync_args = rsync_args.args[:]
@ -89,11 +101,14 @@ class RSync(_base.BaseFetcher):
warnings.warn(errmsg) warnings.warn(errmsg)
return(None) return(None)


def fetch_content(self, remote_filepath): def fetch_content(self, remote_filepath, mtime_only = False):
tf = tempfile.mkstemp()[1] tf = tempfile.mkstemp()[1]
url = os.path.join(self.url.rstrip('/'),remote_filepath.lstrip('/')) url = os.path.join(self.url.rstrip('/'), remote_filepath.lstrip('/'))
rsync_args = self.rsync_args[:]
if mtime_only and not any((('--times' in rsync_args), ('-t' in rsync_args))):
rsync_args.insert(0, '--times')
cmd_str = ['rsync', cmd_str = ['rsync',
*self.rsync_args, *rsync_args,
url, url,
tf] tf]
_logger.debug('Running command: {0}'.format(' '.join(cmd_str))) _logger.debug('Running command: {0}'.format(' '.join(cmd_str)))
@ -119,8 +134,11 @@ class RSync(_base.BaseFetcher):
_logger.error(errmsg) _logger.error(errmsg)
_logger.debug(debugmsg) _logger.debug(debugmsg)
warnings.warn(errmsg) warnings.warn(errmsg)
with open(tf, 'rb') as fh: if mtime_only:
raw_content = fh.read() raw_content = datetime.datetime.fromtimestamp(os.stat(tf).st_mtime)
else:
with open(tf, 'rb') as fh:
raw_content = fh.read()
os.remove(tf) os.remove(tf)
return(raw_content) return(raw_content)



View File

@ -115,6 +115,11 @@ class Mount(object):
return(None) return(None)




class TimeOffset(object):
def __init__(self, duration_str):
self.mod, self.offset = get_duration(duration_str)


class TimestampFile(object): class TimestampFile(object):
def __init__(self, ts_xml, owner_xml = None): def __init__(self, ts_xml, owner_xml = None):
self.xml = ts_xml self.xml = ts_xml
@ -197,16 +202,18 @@ class Upstream(object):
self.port = constants.PROTO_DEF_PORTS[self.sync_type] self.port = constants.PROTO_DEF_PORTS[self.sync_type]
self.available = None self.available = None
if self.sync_type == 'rsync': if self.sync_type == 'rsync':
self.fetcher = fetcher.RSync(self.domain, _fetcher = fetcher.RSync
self.port,
self.path,
self.dest,
rsync_args = rsync_args,
rsync_ignores = rsync_ignores,
filechecks = self.filechecks,
owner = self.owner)
else: else:
self.fetcher = fetcher.FTP(self.domain, self.port, self.path, self.dest, owner = self.owner) _fetcher = fetcher.FTP
self.fetcher = _fetcher(self.domain,
self.port,
self.path,
self.dest,
rsync_args = rsync_args,
rsync_ignores = rsync_ignores,
filechecks = self.filechecks,
offset = self.offset,
owner = self.owner)
self._check_conn() self._check_conn()


def _check_conn(self): def _check_conn(self):
@ -224,14 +231,15 @@ class Upstream(object):
delay = self.xml.attrib.get('delayCheck') delay = self.xml.attrib.get('delayCheck')
if not delay: if not delay:
return(None) return(None)
mod, self.delay = get_duration(delay) delay = TimeOffset(delay)
self.delay = delay.offset
return(None) return(None)


def _get_offset(self): def _get_offset(self):
offset = self.xml.attrib.get('offset') offset = self.xml.attrib.get('offset')
if not offset: if not offset:
return(None) return(None)
self.offset = get_duration(offset) self.offset = TimeOffset(offset)
return(None) return(None)


def sync(self): def sync(self):