Nothing
#' Configure SASPy package
#'
#' @description
#' Adds `sascfg_personal.py` and `authinfo` files and prefills relevant info
#' according to a specified template.
#'
#' @param template Default template to base configuration files off of.
#' @param overwrite Can new configuration files overwrite existing config files (if they exist)?
#'
#' @details
#' Configuration for SAS can vary greatly based on your computer's operating
#' system and the SAS platform you wish to connect to (see
#' `vignette("configuration")` for more information).
#'
#' Regardless of your desired configuration, configuration always starts with
#' the creation of a `sascfg_personal.py` file within the `SASPy` package
#' installation. This will look like:
#'
#' ```
#' SAS_config_names = ['config_name']
#'
#' config_name = {
#'
#' }
#' ```
#'
#' `SAS_config_names` should contain a string list of the variable names
#' of all configurations. Configurations are specified as dictionaries,
#' and configuration parameters depend on the access method.
#'
#' Additionally, some access methods will require an additional
#' authentication file (`.authinfo` for Linux and Mac, `_authinfo`
#' for Windows) stored in the user's home directory, which are
#' constructed as follows:
#'
#' ```
#' config_name user {your username} password {your password}
#' ```
#'
#' ### Templates
#'
#' The `"none"` template simply creates a `sascfg_personal.py` file within
#' the `SASPy` package installation.
#'
#' The `"oda"` template will set up a configuration for SAS On Demand for
#' Academics. The `sascfg_personal.py` and `authinfo` files will be
#' automatically configured using the information you provide through prompts.
#'
#' @return No return value.
#'
#' @export
#'
#' @seealso [install_saspy()]
#' @examplesIf interactive()
#'
#' # set up an ODA connection
#' config_saspy(template = "oda")
configure_saspy <- function(
template = c("none", "oda"),
overwrite = FALSE
) {
template <- rlang::arg_match(template, c("none", "oda"))
saspy_path <- get_saspy_path()
if (template == "none") {
configs <- list(config_name = list())
} else if (template == "oda") {
java_path <- check_java_installation(saspy_path)
iom_host <- ask_oda_server()
configs <- list(
oda = list(
java = java_path,
iomhost = iom_host,
iomport = 8591L,
encoding = "utf-8",
authkey = "oda"
)
)
}
write_sascfg_personal(configs, saspy_path, overwrite)
if (template == "oda") {
write_authinfo_template(overwrite)
sas_oda_jar_dir <- paste0(saspy_path, "/java/iomclient/")
cli::cli_inform(c(
"i" = "Download and extract the SAS ODA zip encryption jars ({.url https://support.sas.com/downloads/package.htm?pid=2494}) into {.file {sas_oda_jar_dir}}."
))
}
cli::cli_inform(c(
"i" = "For more information about {.pkg SASPy} configuration see the {.vignette [Configuration](sasquatch::configuration)} vignette or the {.href [SASPy documentation](https://sassoftware.github.io/saspy/configuration.html)}."
))
invisible()
}
get_saspy_path <- function() {
python_config <- reticulate::py_discover_config("saspy", "r-saspy")
python_path <- python_config$python
saspy_path <- python_config$required_module_path
if (is.null(saspy_path)) {
cli_python_path <- ifelse(
is.null(python_path),
"",
paste0(" within ", python_path)
)
cli_msg <- c(
"x" = "No SASPy installation found{cli_python_path}."
)
if (!is.null(python_config$forced)) {
cli_msg <- c(
cli_msg,
"i" = "Python version was forced by {python_config$forced}.",
"i" = "If SASPy is installed elsewhere, set the Python version with {.fun reticulate::use_python}, {.fun reticulate::use_virtualenv}, {.fun reticulate::use_conda}, or {.fun reticulate::use_miniconda}.",
"i" = "Else, use {.fun sasquatch::install_saspy} and {.fun reticulate::use_virtualenv} to install SASPy within a virtual env and set it as your Python version."
)
} else {
cli_msg <- c(
cli_msg,
"i" = "Use {.fun sasquatch::install_saspy} to install SASPy within a virtual env."
)
}
cli::cli_abort(cli_msg)
}
saspy_path
}
check_java_installation <- function(saspy_path) {
java_path <- Sys.which("java")
if (identical(unname(java_path), "")) {
sascfg_personal_path <- paste0(saspy_path, "/sascfg_personal.py")
cli::cli_warn(
"No java installation found. Enter the java path manually within {.file {sascfg_personal_path}}."
)
}
java_path
}
ask_oda_server <- function() {
oda_servers <- list(
"United States 1" = list(
'odaws01-usw2.oda.sas.com',
'odaws02-usw2.oda.sas.com',
'odaws03-usw2.oda.sas.com',
'odaws04-usw2.oda.sas.com'
),
"United States 2" = list(
'odaws01-usw2-2.oda.sas.com',
'odaws02-usw2-2.oda.sas.com'
),
"Europe 1" = list('odaws01-euw1.oda.sas.com', 'odaws02-euw1.oda.sas.com'),
"Asia Pacific 1" = list(
'odaws01-apse1.oda.sas.com',
'odaws02-apse1.oda.sas.com'
),
"Asia Pacific 2" = list(
'odaws01-apse1-2.oda.sas.com',
'odaws02-apse1-2.oda.sas.com'
)
)
cli::cli_inform("Which server is your account on?")
server_num <- utils::menu(
names(oda_servers)
)
if (server_num == 0L) {
cli::cli_abort("Server location required to create SAS ODA configuration.")
}
oda_servers[[server_num]]
}
write_authinfo_template <- function(
overwrite,
call = rlang::caller_env()
) {
if (.Platform$OS.type == "windows") {
authinfo_path <- paste0(get_home_dir(), "/_authinfo")
} else {
authinfo_path <- paste0(get_home_dir(), "/.authinfo")
}
if (!overwrite) {
check_no_file(authinfo_path, call)
}
authinfo <- "oda user {username} password {password}\n"
write_file(
message = "SASPy requires you to store ODA credentials in a authinfo file stored in\n\n - {.file {file}}\n\nIs it okay to create a template file at this path?",
file = authinfo_path,
authinfo
)
cli::cli_inform(c(
"i" = "Replace {.str {{username}}} and {.str {{password}}} with your ODA username and password within {.file {authinfo_path}}."
))
if (rstudioapi::hasFun("navigateToFile")) {
rstudioapi::navigateToFile(authinfo_path)
}
}
get_home_dir <- function() {
home_dir <- Sys.getenv("HOME")
if (.Platform$OS.type == "windows") {
home_dir <- regmatches(home_dir, regexpr("(.*?[/|\\\\]){3}", home_dir))
}
sub("[/|\\\\]$", "", home_dir)
}
write_sascfg_personal <- function(
configs,
saspy_path,
overwrite,
call = rlang::caller_env()
) {
sascfg_personal_path <- paste0(saspy_path, "/sascfg_personal.py")
if (!overwrite) {
check_no_file(sascfg_personal_path, call)
}
config_list <- paste0(
"SAS_config_names = ",
reticulate::r_to_py(list(names(configs)))
)
config_dicts <- vapply(
names(configs),
function(config_name) {
paste(
config_name,
"=",
as.character(reticulate::dict(configs[[config_name]]))
)
},
FUN.VALUE = character(1)
)
contents <- paste(
config_list,
paste(config_dicts, collapse = "\n\n"),
"",
sep = "\n"
)
write_file(
message = "SASPy utilizes a configuration file stored within the SASPy package itself at\n\n - {.file {file}}\n\nIs it okay to create a configuration file at this path?",
file = sascfg_personal_path,
contents
)
sascfg_personal_path
}
write_file <- function(..., file, message = NULL) {
if (!is.null(message)) {
cli::cli_alert(
message
)
server_num <- utils::menu(c("Yes", "No"))
if (server_num == 2L) {
cli::cli_abort("Unable to write to {.file {file}}.")
}
}
cli::cli_alert_success("Writing to {.path {file}}.")
cat(..., file = file)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.