sftp-directory-mirror.py 3.34 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
#!/usr/bin/python3
import os
import sys
import argparse
from helperslib import BuildSpecs, BuildSystem, CommonUtils, EnvironmentHandler, Packages

# Parse the command line arguments we've been given
parser = argparse.ArgumentParser(description='Utility to transfer a given directory to a given location on a remote system over SFTP.')
parser.add_argument('--source', type=str, required=True)
parser.add_argument('--destination', type=str, required=True)
parser.add_argument('--server', type=str, required=True)
parser.add_argument('--username', type=str, required=True)
arguments = parser.parse_args()

# Let's establish a connection to the remote system
# We assume the private key file is password-less
privateKeyFile = os.path.join( os.path.expanduser('~'), 'Keys', 'Uploader.key')
uploadConnection = CommonUtils.establishSSHConnection( arguments.server, arguments.username, privateKeyFile )
# Open the SFTP connection
sftp = uploadConnection.open_sftp()

# Step 1: Make sure the remote destination exists
# As a sanity mechanism, we don't continue if it does not in case there is a typo or something else (the remote admin should be creating it in advance for us)
24
if not CommonUtils.sftpFileExists( sftp, arguments.destination ):
25 26 27 28
	print("Destination does not exist on the remote server - cannot continue!")
	sys.exit(1)

# Step 2: Start recursing through our local copy and uploading files
Ben Cooksley's avatar
Ben Cooksley committed
29
for root, directories, files in os.walk( arguments.source ):
30 31 32 33 34 35 36 37
	# First we need to make our root relative
	relativeRoot = os.path.relpath( root, arguments.source )
	# Now we can determine our remote prefix for this iteration
	remotePrefix = os.path.join( arguments.destination, relativeRoot )

	# First we check the directories to see if any need to be created
	for directory in directories:
		# Determine what it's full remote path would be
Ben Cooksley's avatar
Ben Cooksley committed
38
		# Because SFTP works with forward not backslashes we have to translate those before use
39
		remoteDirectory = os.path.join( remotePrefix, directory )
Ben Cooksley's avatar
Ben Cooksley committed
40
		remoteDirectory = remoteDirectory.replace('\\', '/')
41
		# Now check to see if it exists..
42
		if not CommonUtils.sftpFileExists( sftp, remoteDirectory ):
43 44 45 46 47 48
			# And create it if it doesn't exist...
			sftp.mkdir( remoteDirectory )

	# Now we can handle files!
	for filename in files:
		# Determine what it's full local and remote paths are
Ben Cooksley's avatar
Ben Cooksley committed
49
		# Because SFTP works with forward not backslashes we have to translate those before use
50 51
		localPath = os.path.join( root, filename )
		remotePath = os.path.join( remotePrefix, filename )
Ben Cooksley's avatar
Ben Cooksley committed
52
		remotePath = remotePath.replace('\\', '/')
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77

		# Prepare to begin checking whether we need to upload a file
		# By default we don't need to upload
		needToUpload = False

		# If any exception is raised we will assume we need to upload the file
		try:
			# First, let's stat the file on the server
			# If it doesn't exist this will fail with an exception, and we'll upload the file
			sftpStat = sftp.stat( remotePath )
			# We will need a local stat() to compare it to as well
			localStat = os.stat( localPath )
			# If the filesize differs, or if the local file is newer we need to upload
			if localStat.st_size != sftpStat.st_size or localStat.st_mtime > sftpStat.st_mtime:
				needToUpload = True

		# If anything went wrong then we need to upload!
		except IOError:
			needToUpload = True
			pass

		# Do we need to upload?
		if needToUpload:
			# Upload the file!
			sftp.put( localPath, remotePath )