OpenMiInk/third_party/kde-ci-utilities/sftp-directory-mirror.py
Hellings b8c8ff98e2 Hi
2026-10-16 09:05:56 -04:00

95 lines
4.1 KiB
Python
Executable file

#!/usr/bin/python3
import os
import sys
import argparse
import paramiko
def establishSSHConnection( hostname, username, keyFile ):
# Load the private key file
serverAccessKey = paramiko.RSAKey.from_private_key(keyFile)
# Initiate connection to the upload host
client = paramiko.SSHClient()
client.set_missing_host_key_policy( paramiko.client.AutoAddPolicy() )
client.connect( hostname, username=username, pkey = serverAccessKey )
# All done
return client
def sftpFileExists(sftpConnection, pathToFile):
# Try to stat the file
# If it succeeds, then it exists, otherwise an exception is thrown
try:
sftpConnection.stat(pathToFile)
return True
except IOError:
return False
# 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 = open(os.environ['CRAFT_UPLOAD_KEY'], 'r')
uploadConnection = 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)
if not sftpFileExists( sftp, arguments.destination ):
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
for root, directories, files in os.walk( arguments.source ):
# 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
# Because SFTP works with forward not backslashes we have to translate those before use
remoteDirectory = os.path.join( remotePrefix, directory )
remoteDirectory = remoteDirectory.replace('\\', '/')
# Now check to see if it exists..
if not sftpFileExists( sftp, remoteDirectory ):
# 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
# Because SFTP works with forward not backslashes we have to translate those before use
localPath = os.path.join( root, filename )
remotePath = os.path.join( remotePrefix, filename )
remotePath = remotePath.replace('\\', '/')
# 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
# Do we need to upload?
if needToUpload:
# Upload the file!
sftp.put( localPath, remotePath )