kinetic-devel/bin/rossync

200 lines
7.2 KiB
Python
Executable File

#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2009, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of the Willow Garage nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Revision $Id$
import os
import sys
import roslib.packages
import roslib.scriptutil as s
from subprocess import Popen, PIPE
from optparse import OptionParser
parser = OptionParser(usage="usage: %prog machine package(s)", prog='rossync')
parser.add_option("-3", "--include-3rdparty",
dest="thirdparty", default=False, action="store_true",
help="include 3rdparty package in sync")
parser.add_option("-n", "--dry-run",
dest="dryrun", default=False, action="store_true",
help="dry run; print what would be done")
parser.add_option("-v", "--verbose",
dest="verbose", default=False, action="store_true",
help="verbose output")
parser.add_option("-s", "--no-svn",
dest="nosvn", default=False, action="store_true",
help="don't include .svn directories in intermediate directories")
parser.add_option("-f", "--force",
dest="force", default=False, action="store_true",
help="overwrite files on the remote machine, even if they are newer than those on the local machine (DANGEROUS)")
parser.add_option("-p", "--progress",
dest="progress", default=False, action="store_true",
help="show progress during rsync (same as --progress option to rsync)")
parser.add_option("-d", "--no-deps",
dest="nodeps", default=False, action="store_true",
help="sync only the named packages, without their dependencies")
options, args = parser.parse_args()
# TODO: Expose a convenient way to extend and/or replace this pattern list
ignore_patterns = ['.*.swp', '.svn/lock']
if len(args) < 2:
parser.error("please specify a machine and target package(s)")
machine = args[0]
targets = args[1:]
# Does the user have rsync installed?
command = ['which', 'rsync']
res = Popen(command, stdout=PIPE).communicate()[0]
if res == '':
print 'ERROR: Cannot execute rsync. Please install it.'
print ' On Ubuntu / Debian systems:'
print ' sudo apt-get install rsync'
sys.exit(-1)
# load up the package directory cache
roslib.packages.list_pkgs()
# Gather the roots that we may need to create on the other side
roots = [os.environ['ROS_ROOT']]
for d in os.environ['ROS_PACKAGE_PATH'].split(':'):
if d != '':
roots.append(d)
if options.nodeps:
pkgs = targets
pkgs = list(set(pkgs)) #uniq
pkg_dirs = [roslib.packages.get_pkg_dir(p) for p in pkgs]
else:
print "[rossync] Computing dependencies"
# Start with packages that everyone needs, but noone depends on
pkgs = ['rospack', 'rosbash', 'rostopic', 'rosout', 'mk', 'rosbuild', 'rosviz', 'rosparam']
# For now we must have all client libraries installed, because rosbuild
# fails if it doesn't find any of them; this will be fixed.
pkgs.extend(['roscpp', 'rospy', 'roslisp', 'rosoct'])
for t in targets:
pkgs.append(t)
pkgs.extend(s.rospack_depends(t))
pkgs = list(set(pkgs)) #uniq
pkg_dirs = [roslib.packages.get_pkg_dir(p) for p in pkgs]
# Also throw in non-package directories that everyone needs
pkg_dirs.extend([os.path.join(os.environ['ROS_ROOT'],'config'),
os.path.join(os.environ['ROS_ROOT'],'bin')])
sync_dirs = []
dir_map = {}
for p in pkg_dirs:
# exclude thirdparty by default
if not options.thirdparty and '3rdparty' in p:
if options.verbose:
print "[rossync] Excluding thirdparty package", p
continue
sync_dirs.append(p)
newp = None
for r in roots:
nr = os.path.normpath(r)
# Should really use os.path facilities here, but they don't seem to
# offer a convenient way to split a path into a list of its component
# pieces. So for now we'll be UNIX-specific.
if '/'.join(p.split('/')[0:len(nr.split('/'))]) == nr:
newp = ['/'.join(p.split('/')[len(nr.split('/')):])]
if not options.nosvn:
d = os.path.dirname(p)
while len(d) >= len(nr):
svn = os.path.join(d,'.svn')
if os.path.exists(svn):
newsvn = '/'.join(svn.split('/')[len(nr.split('/')):])
newp.append(newsvn)
sync_dirs.append(newsvn)
d = os.path.dirname(d)
break
if newp is None:
print '[rossync] Failed to find valid root path for %s. Aborting' % (p)
sys.exit(-1)
if nr in dir_map:
dir_map[nr].extend(newp)
else:
dir_map[nr] = newp
print "[rossync] Creating the following directories on %s" %(machine)
for r in roots:
print "[rossync] %s"%(r)
command = ['ssh', machine, 'mkdir', '-p', r]
command = ' '.join(command)
if options.verbose:
print "[rossync] Executing command", command
if not options.dryrun:
Popen(command, shell=True).communicate()[0]
if options.verbose:
print "[rossync] Will sync %d directories: "%len(sync_dirs)+' '.join(sync_dirs)
else:
print "[rossync] Will sync %d directories"%len(sync_dirs)
print "[rossync] This will require %d rsync command(s)"%len(dir_map.keys())
for parent_dir in dir_map:
if options.verbose:
print '[rossync] Changing directory to %s' % (parent_dir)
os.chdir(parent_dir)
command = ['rsync']
if options.force:
command.append('-aRze')
else:
command.append('-aRuze')
command.append('ssh')
if options.progress:
command.append('--progress')
for p in ignore_patterns:
command.append('--exclude=%s'%(p))
command = command + dir_map[parent_dir] + ["%s:%s"%(machine, parent_dir)]
command = ' '.join(command)
if options.verbose:
print "[rossync] Executing command", command
else:
print "[rossync] Syncing %s"%(parent_dir)
if not options.dryrun:
Popen(command, shell=True).communicate()[0]
print 'Done.'