aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'roverlay/remote/rsync.py')
-rw-r--r--roverlay/remote/rsync.py86
1 files changed, 86 insertions, 0 deletions
diff --git a/roverlay/remote/rsync.py b/roverlay/remote/rsync.py
new file mode 100644
index 0000000..e46d1db
--- /dev/null
+++ b/roverlay/remote/rsync.py
@@ -0,0 +1,86 @@
+import os
+import subprocess
+
+from roverlay import config
+from roverlay.util import keepenv
+
+
+RSYNC_ENV = keepenv (
+ 'PATH',
+ 'USER',
+ 'LOGNAME',
+ 'RSYNC_PROXY',
+ 'RSYNC_PASSWORD',
+)
+
+
+# --recursive is not in the default opts, subdirs in CRAN/contrib are
+# either R release (2.xx.x[-patches] or the package archive)
+DEFAULT_RSYNC_OPTS = (
+ '--links', # copy symlinks as symlinks,
+ '--safe-links', # but ignore links outside of tree
+ '--times', #
+ '--compress', # FIXME: add lzo if necessary
+ '--delete', #
+ '--force', # allow deletion of non-empty dirs
+ '--human-readable', #
+ '--stats', #
+ '--chmod=ugo=r,u+w,Dugo+x', # 0755 for transferred dirs, 0644 for files
+)
+
+class RsyncJob ( object ):
+ def __init__ (
+ self, remote=None, distdir=None, run_now=True, extra_opts=None
+ ):
+ self.remote = remote
+ self.distdir = distdir
+ self.extra_opts = None
+
+ if run_now: self.run()
+ # --- end of __init__ (...) ---
+
+ def _rsync_argv ( self ):
+ if self.remote is None or self.distdir is None:
+ raise Exception ( "None in (remote,distdir)." )
+
+ argv = [ 'rsync' ]
+
+ argv.extend ( DEFAULT_RSYNC_OPTS )
+
+ max_bw = config.get ( 'RSYNC_BWLIMIT', None )
+ if max_bw is not None:
+ argv.append ( '--bwlimit=%i' % max_bw )
+
+ if self.extra_opts is not None:
+ if isinstance ( self.extra_opts, str ) or \
+ not hasattr ( self.extra_opts, '__iter__' )\
+ :
+ argv.append ( self.extra_opts )
+ else:
+ argv.extend ( self.extra_opts )
+
+ argv.extend ( ( self.remote, self.distdir ) )
+
+ return argv
+ # --- end of _rsync_argv (...) ---
+
+ def run ( self ):
+
+ rsync_cmd = self._rsync_argv()
+
+ os.makedirs ( self.distdir, exist_ok=True )
+
+ # TODO pipe/log/.., running this in blocking mode until implemented
+
+ proc = subprocess.Popen (
+ rsync_cmd,
+ stdin=None, stdout=None, stderr=None,
+ env=RSYNC_ENV
+ )
+
+ if proc.communicate() != ( None, None ):
+ raise AssertionError ( "expected None,None from communicate!" )
+
+ self.returncode = proc.returncode
+
+ # --- end of start (...) ---