SFTP in R on a Mac | Jason Bryer

SFTP in R on a Mac

I am working on a project where I need to upload PDFs generated from Rmarkdown to a SFTP server. The sftp R package is a nice wrapper to the RCurl package for handling SFTP access. But to my surprise, SFTP support is not included on Macs by default through the curl command. After some research I found the curl-openssl formula that includes SFTP support. However, since curl is a build-in program for Mac OS brew install will not install it into the PATH environment, therefore not being directly available. This function will help configure RCurl on a Mac to use the curl-openssl version so we can have SFTP access.

# First, need to install a version of CURL that supports SFTP
# brew install curl-openssl
# Verify that SFTP is a supported protocol
# /opt/homebrew/Cellar/curl/7.82.0/bin/curl -V

#' Configures CURL with openSSL support for Macs.
#'
#' This function will try the following:
#' 1. Verify that this is being called on a Mac.
#' 2. Check to see if sftp is already available (returns gracefully so to be
#'  integrated in setup scripts).
#' 3. Checks to see if Homebrew is installed even if not currently on the PATH.
#' 4. Install curl-openssl if not already installed.
#' 5. Modify the PATH to include the openssl version of curl.
#' 6. Install RCurl from source.
#' 7. Verify sftp is available.
#'
#' @param path the path where Homebrew packages are installed.
#' @return TRUE if sftp is available.
configure_curl_openssl <- function(
	path = '/opt/homebrew/Cellar'
) {
	if(Sys.info()['sysname'] != 'Darwin') {
		warning('This funtion only works on Mac OS.')
		return(FALSE)
	}
	if(system('which brew') == 1) {
		if(file.exists('/opt/homebrew/bin/brew')) {
			# Homebrew is installed but not on the PATH
			PATH <- Sys.getenv("PATH")
			Sys.setenv(PATH = paste("/opt/homebrew/bin", PATH, sep = ":"))
		} else {
			stop('Could not find brew. Try installing from https://brew.sh')
		}
	}
	if('sftp' %in% RCurl::curlVersion()$protocols) {
		return(TRUE)
	}

	curl.versions <- list.dirs(path = paste0(path, '/curl/'),
							   recursive = FALSE,
							   full.names = FALSE)
	if(length(curl.versions) == 0) { # Try install curl
		message('curl-openssl not found, trying to install using Homebrew...')
		system('brew install curl-openssl')
		curl.versions <- list.dirs(path = paste0(path, '/curl/'),
								   recursive = FALSE,
								   full.names = FALSE)
	}
	if(length(curl.versions) == 0) {
		stop('Could not find or install curl-openssl.')
	}
	version <- curl.versions[length(curl.versions)] # Use the latest version
	if('package:RCurl' %in% search()) { # Detach the RCurl package first
		detach('package:RCurl', character.only = TRUE)
	}
	PATH <- Sys.getenv("PATH")
	Sys.setenv(PATH = paste0("/opt/homebrew/Cellar/curl/", version, "/bin:", PATH))
	message('Resinstalling RCurl from source...')
	install.packages('RCurl', type = 'source')
	if(!'sftp' %in% RCurl::curlVersion()$protocols) {
		stop('Could not configure RCurl with openssl, sorry.')
	}
	return(TRUE)
}

Simply running the command should do the setup. However, if things go wrong I tried to indicate where in the process something went wrong. You should only need to run this once per R installation since once RCurl has been installed from source built against the curl-openssl version of CURL, it should remember to use that version.

configure_curl_openssl()

Once done, we can verify that SFTP access is available.

'sftp' %in% RCurl::curlVersion()$protocols # Verify sftp is available

Related

comments powered by Disqus