#' @title Check package dependencies
#' @description The function allows to graphically check that all the
#' optional runtime dependencies are installed.
#' @return NULL (the function is called for its side effects)
#' @details This package needs some external dependencies in order to run
#' specific actions:
#' - Sen2Cor for atmospheric correction;
#' - GDAL for cloud mask smoothing and buffering;
#' - aria2 to download SAFE images with an alternative downloader.
#'
#' This function opens a GUI which allows to check that these dependencies
#' are installed. This check is highly suggested before using the library for
#' the fist time, in order to avoid errors.
#' @author Luigi Ranghetti, phD (2019)
#' @references L. Ranghetti, M. Boschetti, F. Nutini, L. Busetto (2020).
#' "sen2r": An R toolbox for automatically downloading and preprocessing
#' Sentinel-2 satellite data. _Computers & Geosciences_, 139, 104473.
#' \doi{10.1016/j.cageo.2020.104473}, URL: \url{https://sen2r.ranghetti.info/}.
#' @note License: GPL 3.0
#' @importFrom utils capture.output
#' @importFrom httr RETRY write_disk progress
#' @importFrom jsonlite fromJSON toJSON
#' @export
#' @examples
#' if (interactive()) {
#' check_sen2r_deps()
#' }
check_sen2r_deps <- function() {
jscode <- "shinyjs.closeWindow = function() { window.close(); }"
# Check shiny* / leaflet* suggested dependencies to be installed
check_gui_deps()
# Define internal functions as aliases of shiny* - leaflet* ones,
# so to avoid using "shiny::" every time
a <- shiny::a
actionButton <- shiny::actionButton
addResourcePath <- shiny::addResourcePath
br <- shiny::br
code <- shiny::code
column <- shiny::column
conditionalPanel <- shiny::conditionalPanel
disable <- shinyjs::disable
disabled <- shinyjs::disabled
div <- shiny::div
em <- shiny::em
enable <- shinyjs::enable
extendShinyjs <- shinyjs::extendShinyjs
fluidPage <- shiny::fluidPage
fluidRow <- shiny::fluidRow
getVolumes <- shinyFiles::getVolumes
h3 <- shiny::h3
helpText <- shiny::helpText
hide <- shinyjs::hide
hr <- shiny::hr
HTML <- shiny::HTML
html <- shinyjs::html
htmlOutput <- shiny::htmlOutput
icon <- shiny::icon
modalButton <- shiny::modalButton
modalDialog <- shiny::modalDialog
observe <- shiny::observe
observeEvent <- shiny::observeEvent
outputOptions <- shiny::outputOptions
p <- shiny::p
parseDirPath <- shinyFiles::parseDirPath
parseFilePaths <- shinyFiles::parseFilePaths
radioButtons <- shiny::radioButtons
reactive <- shiny::reactive
reactiveFileReader <- shiny::reactiveFileReader
reactivePoll <- shiny::reactivePoll
reactiveValues <- shiny::reactiveValues
removeModal <- shiny::removeModal
renderText <- shiny::renderText
renderUI <- shiny::renderUI
runApp <- shiny::runApp
shinyApp <- shiny::shinyApp
shinyDirButton <- shinyFiles::shinyDirButton
shinyDirChoose <- shinyFiles::shinyDirChoose
shinyFileChoose <- shinyFiles::shinyFileChoose
shinyFilesButton <- shinyFiles::shinyFilesButton
showModal <- shiny::showModal
span <- shiny::span
stopApp <- shiny::stopApp
strong <- shiny::strong
textInput <- shiny::textInput
textOutput <- shiny::textOutput
uiOutput <- shiny::uiOutput
updateTextInput <- shiny::updateTextInput
useShinyjs <- shinyjs::useShinyjs
verbatimTextOutput <- shiny::verbatimTextOutput
# get server volumes
volumes <- c(
"Home" = normalize_path("~"),
"sen2r" = system.file(package = "sen2r"),
getVolumes()()
)
settings.ui <- fluidPage(
# header
shinyjs::useShinyjs(),
extendShinyjs(text = jscode, functions = c("closeWindow")),
fluidRow(column(
title="Dependencies",
width=12,
h3("Google Cloud SDK"),
helpText(em(
"Google Cloud SDK is used to search and download Sentinel-2 SAFE",
"archives from Google Cloud.",
"It must be installed and configured externally following the",
a("official instructions.",
href='https://cloud.google.com/sdk/docs/install',
target='_blank'),
"Done that, use this utility to associate it to sen2r."
)),
span(style="display:inline-block;vertical-align:center;padding-top:5px;",
actionButton("where_check_gcloud", "Check Google Cloud SDK", width=200),
"\u2000"),
span(style="display:inline-block;vertical-align:center;",
htmlOutput("check_gcloud_icon")),
h3("Sen2Cor"),
helpText(em(
"Sen2Cor is used to perform atmospheric correction of Sentinel-2",
"Level-1C products: it is required by the package,",
"unless you choose not to correct products locally",
"(using only Level-1C \u2013 TOA products",
"or downloading directly Level-2A products)."
)),
span(style="display:inline-block;vertical-align:center;padding-top:5px;",
actionButton("check_sen2cor", "Check Sen2Cor", width=200),
"\u2000"),
span(style="display:inline-block;vertical-align:center;",
htmlOutput("check_sen2cor_icon")),
h3("GDAL"),
helpText(em(
"An external GDAL runtime environment is", strong("no more needed"),
"to run sen2r",
"(it is only required in order to smooth / buffer a cloud mask,",
"and", strong("optionally"), "used to compute spectral indices,",
"RGB images and thumbnails).",
if (Sys.info()["sysname"] == "Windows") {span(
"On Windows",
strong("it is strictly required to install GDAL using OSGeo4W"),
"in order to avoid errors.",
"To satisfy this requirement, click on \"Check GDAL\" and,",
"whenever the search of a valid installation will finish, download",
"the OSGeo4W installer and install it in the default directory",
"(or, in any case, maintain the directory name \"OSGeo4W64\")."
)}
)),
helpText(em(
span(style = "color:red;font-weight:bold;", "Note:"),
"Configuring a runtime GDAL environment could fail for different reasons",
"(e.g. problems related to GDAL environment like missing libraries,",
"or custom environment variables which could conflict).",
"sen2r maintainers are not responsible in case of GDAL-related issues."
)),
span(style="display:inline-block;vertical-align:center;padding-top:5px;",
actionButton("where_check_gdal", "Check GDAL", width=200),
"\u2000"),
span(style="display:inline-block;vertical-align:center;",
htmlOutput("check_gdal_icon")),
h3("aria2"),
helpText(em(
"aria2 is an alternative unrequired", strong("(optional)"),
"downloader which can be used to download SAFE archives.",
"Since the number of concurrent downloads from ESA SciHub is limited to 2,",
"the use of aria2 is generally not faster than the default downloader;",
"for this reason, its use is recommended only in case of problems with",
"the default downloader."
)),
span(style="display:inline-block;vertical-align:center;padding-top:5px;",
actionButton("check_aria2", "Check aria2", width=200),
"\u2000"),
span(style="display:inline-block;vertical-align:center;",
htmlOutput("check_aria2_icon")),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
uiOutput("footer_buttons")
)) # end of fluidRow Dependencies
) # end of fluidPage
settings.server <- function(input, output, session) {
# link to www directory and objects
addResourcePath("www", system.file("www", package="sen2r"))
rv <- reactiveValues()
# output OS name (to be used in conditionalPanel)
output$os_name <- renderText(Sys.info()["sysname"])
outputOptions(output, "os_name", suspendWhenHidden = FALSE)
# list of dependencies
dependencies <- c(
"gdalbuildvrt", "gdal_translate", "gdalwarp", "gdal_calc", "gdaldem", "gdalinfo", "ogrinfo",
"python", "sen2cor"
)
# load binpaths
binpaths <- reactivePoll(1000, session, function() {}, load_binpaths)
##-- Perform checks of dependencies --##
#-- Check Google Cloud SDK --#
# build the icon of the check
observe({
rv$check_gcloud_isvalid <- if (!is.null(binpaths()$gsutil)) {
file.exists(binpaths()$gsutil)
} else {FALSE}
})
output$check_gcloud_isvalid <- renderText(rv$check_gcloud_isvalid)
output$check_gcloud_icon <- renderUI({
if (is.na(rv$check_gcloud_isvalid)) {
""
} else if (rv$check_gcloud_isvalid) {
span(style="color:darkgreen;", "\u2714")
} else {
span(style="color:red;", "") #"\u2718")
}
})
outputOptions(output, "check_gcloud_isvalid", suspendWhenHidden = FALSE)
# build the modal dialog
check_gcloud_modal <- reactive({
modalDialog(
title = "Google Cloud SDK check",
size = "s",
uiOutput("check_gcloud_message"),
verbatimTextOutput("check_gcloud_outmessages"),
easyClose = FALSE,
footer = NULL
)
})
# use a reactive output for install GDAL message
# (this because otherwise it does not react to check_gcloud_valid chages)
output$check_gcloud_message <- renderUI({
if (is.na(rv$check_gcloud_isvalid)) {
div(
align="center",
p(style="text-align:center;font-size:500%;color:darkgrey;",
icon("cog", class = "fa-spin"))
)
} else if (!rv$check_gcloud_isvalid) {
div(
p(style="text-align:center;font-size:500%;color:red;",
icon("times-circle")),
p("Google Cloud SDK needs to be installed or searched in a",
"different directory. To install it, follow the",
a("official instructions.",
href='https://cloud.google.com/sdk/docs/install',
target='_blank')),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
div(style="text-align:right;",
modalButton("\u2000Close", icon = icon("check")))
)
} else if (rv$check_gcloud_isvalid) {
div(
p(style="text-align:center;font-size:500%;color:darkgreen;",
icon("check-circle")),
p("Google Cloud SDK is correctly installed and configured."),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
div(style="text-align:right;",
modalButton("\u2000Close", icon = icon("check")))
)
}
})
# ask where searching gcloud before checking
observeEvent(input$where_check_gcloud, {
showModal(modalDialog(
title = "Check Google Cloud SDK",
size = "s",
radioButtons(
"path_gsutil_isauto", NULL,
choices = c("Search Google Cloud SDK in a default path" = TRUE,
"Specify where Google Cloud SDK should be searched" = FALSE),
selected = TRUE, width = "100%"
),
conditionalPanel(
condition = "input.path_gsutil_isauto == 'FALSE'",
div(
p("Specify the path:"),
div(div(style="display:inline-block;vertical-align:top;width:50pt;",
shinyDirButton(
"path_gdalman_sel", "Select",
"Specify directory in which Google Cloud SDK should be searched"
)),
div(style="display:inline-block;vertical-align:top;width:180px;",
textInput("path_gsutilman_textin", NULL, ""))),
div(style="height:20px;vertical-aling:top;",
htmlOutput("path_gsutilman_errormess"))
)
),
easyClose = FALSE,
footer = div(
disabled(actionButton("check_gcloud_button", strong("\u2000Check"), icon=icon("check"))),
modalButton("\u2000Cancel", icon = icon("ban"))
)
))
})
# check the gdal path
observeEvent(c(input$path_gsutilman_textin, input$path_gsutil_isauto), {
path_gsutilman_errormess <- path_check(
input$path_gsutilman_textin,
mustbe_empty = FALSE,
mustbe_writable = FALSE
)
output$path_gsutilman_errormess <- path_gsutilman_errormess
if (any(
input$path_gsutil_isauto == TRUE,
TRUE %in% attr(path_gsutilman_errormess, "isvalid")
)) {
enable("check_gcloud_button")
} else {
disable("check_gcloud_button")
}
})
shinyDirChoose(input, "path_gdalman_sel", roots = volumes)
observeEvent(input$path_gdalman_sel, {
path_gdalman_string <- parseDirPath(volumes, input$path_gdalman_sel)
updateTextInput(session, "path_gsutilman_textin", value = path_gdalman_string)
})
# do the check when button is pressed
observeEvent(input$check_gcloud_button, {
# reset check value
rv$check_gcloud_isvalid <- NA # FIXME not working
# open modaldialog
showModal(check_gcloud_modal())
shinyjs::html(
"check_gcloud_message",
as.character(div(
align="center",
p(style="text-align:center;font-size:500%;color:darkgrey;",
icon("spinner", class = "fa-pulse"))
))
)
# do the check
withCallingHandlers({
shinyjs::html("check_gcloud_outmessages", "")
rv$check_gcloud_isvalid <- if (input$path_gsutilman_textin == "") {
check_gcloud(abort = FALSE, force = TRUE)
} else {
check_gcloud(
gsutil_dir = input$path_gsutilman_textin,
abort = FALSE, force = TRUE
)
}
},
message = function(m) {
shinyjs::html(id = "check_gcloud_outmessages", html = m$message, add = TRUE)
})
shinyjs::hide("check_gcloud_outmessages")
})
#-- Check GDAL --#
# build the icon of the check
observe({
rv$check_gdal_isvalid <- if (!is.null(binpaths()$gdalinfo)) {
file.exists(binpaths()$gdalinfo)
} else {FALSE}
})
output$check_gdal_isvalid <- renderText(rv$check_gdal_isvalid)
output$check_gdal_icon <- renderUI({
if (is.na(rv$check_gdal_isvalid)) {
""
} else if (rv$check_gdal_isvalid) {
span(style="color:darkgreen;", "\u2714")
} else {
span(style="color:red;", "") #"\u2718")
}
})
outputOptions(output, "check_gdal_isvalid", suspendWhenHidden = FALSE)
# build the modal dialog
check_gdal_modal <- reactive({
modalDialog(
title = "GDAL check",
size = "s",
uiOutput("check_gdal_message"),
verbatimTextOutput("check_gdal_outmessages"),
easyClose = FALSE,
footer = NULL
)
})
# use a reactive output for install GDAL message
# (this because otherwise it does not react to check_gdal_valid chages)
output$check_gdal_message <- renderUI({
if (is.na(rv$check_gdal_isvalid)) {
div(
align="center",
p(style="text-align:center;font-size:500%;color:darkgrey;",
icon("cog", class = "fa-spin"))
)
} else if (!rv$check_gdal_isvalid) {
if (Sys.info()["sysname"] == "Windows") {
div(
p(style="text-align:center;font-size:500%;color:red;",
icon("times-circle")),
p(HTML(
"GDAL needs to be installed or searched in a different directory.",
"To install it:<ol>",
"<li>download the OSGeo4W installer using the button below;</li>",
"<li>when the file will be automatically opened,",
"give the administrator rules when required;</li>",
"<li>choose the \"Advanced install\";</li>",
"<li>continue clicking \"Next\";</li>",
"<li>when the window for choosing the packages to install will appear,",
"check the package \"gdal-python\" and install it.</li></ol>"
)),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
div(style="text-align:right;",
actionButton("install_gdal_button", strong("\u2000Download"), icon=icon("download")),
modalButton("\u2000Cancel", icon = icon("ban")))
)
} else {
div(
p(style="text-align:center;font-size:500%;color:red;",
icon("times-circle")),
p("GDAL needs to be installed or searched in a different directory.",
"To install it, install the package \"python-gdal\",",
"then repeat this check."),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
div(style="text-align:right;",
modalButton("\u2000Close", icon = icon("check")))
)
}
} else if (rv$check_gdal_isvalid) {
div(
p(style="text-align:center;font-size:500%;color:darkgreen;",
icon("check-circle")),
p("GDAL is correctly installed."),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
div(style="text-align:right;",
modalButton("\u2000Close", icon = icon("check")))
)
}
})
# build the modal dialog
install_gdal_modal <- reactive({
modalDialog(
title = "Install GDAL",
size = "s",
uiOutput("install_gdal_message"),
easyClose = FALSE,
footer = NULL
)
})
# ask where searching GDAL before checking
observeEvent(input$where_check_gdal, {
showModal(modalDialog(
title = "Check GDAL",
size = "s",
radioButtons(
"path_gdal_isauto", NULL,
choices = c("Search GDAL in a default path" = TRUE,
"Specify where GDAL should be searched" = FALSE),
selected = TRUE, width = "100%"
),
conditionalPanel(
condition = "input.path_gdal_isauto == 'FALSE'",
div(
p("Specify the path:"),
div(div(style="display:inline-block;vertical-align:top;width:50pt;",
shinyDirButton("path_gdalman_sel", "Select", "Specify directory in which GDAL should be searched")),
div(style="display:inline-block;vertical-align:top;width:180px;",
textInput("path_gdalman_textin", NULL, ""))),
div(style="height:20px;vertical-aling:top;",
htmlOutput("path_gdalman_errormess"))
)
),
easyClose = FALSE,
footer = div(
disabled(actionButton("check_gdal_button", strong("\u2000Check"), icon=icon("check"))),
modalButton("\u2000Cancel", icon = icon("ban"))
)
))
})
# check the gdal path
# observeEvent(input$path_gdalman_textin, {
# path_gdalman_errormess <- path_check(
# input$path_gdalman_textin,
# mustbe_empty = FALSE,
# mustbe_writable = FALSE
# )
# output$path_gdalman_errormess <- path_gdalman_errormess
# })
observeEvent(c(input$path_gdalman_textin, input$path_gdal_isauto), {
path_gdalman_errormess <- path_check(
input$path_gdalman_textin,
mustbe_empty = FALSE,
mustbe_writable = FALSE
)
output$path_gdalman_errormess <- path_gdalman_errormess
if (any(
input$path_gdal_isauto == TRUE,
TRUE %in% attr(path_gdalman_errormess, "isvalid")
)) {
enable("check_gdal_button")
} else {
disable("check_gdal_button")
}
})
shinyDirChoose(input, "path_gdalman_sel", roots = volumes)
observeEvent(input$path_gdalman_sel, {
path_gdalman_string <- parseDirPath(volumes, input$path_gdalman_sel)
updateTextInput(session, "path_gdalman_textin", value = path_gdalman_string)
})
# do the check when button is pressed
observeEvent(input$check_gdal_button, {
# reset check value
rv$check_gdal_isvalid <- NA # FIXME not working
# open modaldialog
showModal(check_gdal_modal())
shinyjs::html(
"check_gdal_message",
as.character(div(
align="center",
p(style="text-align:center;font-size:500%;color:darkgrey;",
icon("spinner", class = "fa-pulse"))
))
)
# do the check
withCallingHandlers({
shinyjs::html("check_gdal_outmessages", "")
rv$check_gdal_isvalid <- check_gdal(
gdal_path = if (input$path_gdalman_textin == "") {
NULL
} else {
input$path_gdalman_textin
},
abort = FALSE, force = TRUE
)
},
message = function(m) {
shinyjs::html(id = "check_gdal_outmessages", html = m$message, add = TRUE)
})
shinyjs::hide("check_gdal_outmessages")
})
# install osgeo
observeEvent(input$install_gdal_button, {
showModal(install_gdal_modal())
# create the text to show in the modaldialog
shinyjs::html(
"install_gdal_message",
as.character(div(
br(),
p(style="color:darkgrey;text-align:center;font-size:500%;","\u23F3"),
p("Wait while the OSGeo4W installer is being downloaded...")
)),
add=FALSE
)
# Download osgeo4w
osgeo4w_url <- paste0(
"http://download.osgeo.org/osgeo4w/osgeo4w-setup-x86",
if (Sys.info()["machine"]=="x86-64") {"_64"},".exe"
)
osgeo4w_path <- tempfile(pattern="dir",fileext = ".exe")
out_bar <- if (all(inherits(stdout(), "terminal"), interactive())) {
NULL
} else {
file(out_bar_path <- tempfile(), open = "a")
}
RETRY(
verb = "GET",
url = osgeo4w_url,
times = 5, pause_cap = 8,
progress(con = if (length(out_bar) > 0) {out_bar} else {stdout()}),
write_disk(osgeo4w_path, overwrite = TRUE)
)
if (length(out_bar) > 0) {
close(out_bar)
invisible(file.remove(out_bar_path))
}
if (file.exists(osgeo4w_path)) {
shinyjs::html(
"install_gdal_message",
as.character(div(
p("OSGeo4W was correctly downloaded."),
p("The installer window was opened;",
"please install the package \"gdal-python\" following the instructions.")
)),
add = TRUE
)
shell(osgeo4w_path)
shinyjs::html(
"install_gdal_message",
as.character(div(
p("The installation was terminated;",
"please close the interface,",strong("restart R"),
"and repeat the check to be sure all was correctly installed."),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
div(style="text-align:right;",
modalButton("\u2000Close", icon = icon("check")))
)),
add = TRUE
)
} else {
shinyjs::html(
"install_gdal_message",
as.character(div(
p("Something went wrong during the download; please retry."),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
div(style="text-align:right;",
modalButton("\u2000Close", icon = icon("check")))
)),
add = TRUE
)
}
})
#-- Check aria2 --#
# build the icon of the check
observe({
input$check_aria2
rv$check_aria2_isvalid <- if (!is.null(binpaths()$aria2c)) {
file.exists(binpaths()$aria2c)
} else {FALSE}
})
output$check_aria2_isvalid <- renderText(rv$check_aria2_isvalid)
output$check_aria2_icon <- renderUI({
if (is.na(rv$check_aria2_isvalid)) {
""
} else if (rv$check_aria2_isvalid) {
span(style="color:darkgreen;", "\u2714")
} else {
span(style="color:red;", "") #"\u2718")
}
})
outputOptions(output, "check_aria2_isvalid", suspendWhenHidden = FALSE)
output$check_aria2_message <- renderUI({
if (is.na(rv$check_aria2_isvalid)) {
""
} else if (!rv$check_aria2_isvalid) {
div(
align = if (Sys.info()["sysname"] == "Windows") {"left"} else {"center"},
p(style="color:red;text-align:center;font-size:500%;",
icon("times-circle")),
if (Sys.info()["sysname"] == "Windows") {
div(
p("aria2 needs to be linked to sen2r, or downloaded if missing."),
radioButtons(
"aria2_link_or_install", NULL,
c("Download a new aria2 binary" = "install",
"Set the path of an existing binary" = "link"),
selected = "install"
),
conditionalPanel(
condition = "input.aria2_link_or_install == 'install'",
div(
p("Please provide the path of a directory ",
"in which installing it:"),
div(div(style="display:inline-block;vertical-align:top;width:50pt;",
shinyDirButton("path_newaria2_sel", "Select", "Specify directory in which installing aria2")),
div(style="display:inline-block;vertical-align:top;width:180px;",
textInput("path_newaria2_textin", NULL, ""))),
div(style="height:20px;vertical-aling:top;",
htmlOutput("path_newaria2_errormess")),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
div(style="text-align:right;",
disabled(actionButton("install_aria2_button", strong("\u2000Download"), icon=icon("download"))),
modalButton("\u2000Cancel", icon = icon("ban")))
)
),
conditionalPanel(
condition = "input.aria2_link_or_install == 'link'",
div(
p("Please provide the path of an existing aria2 binary:"),
div(div(style="display:inline-block;vertical-align:top;width:50pt;",
shinyFilesButton("path_exiaria2_sel", "Select", "Specify the aria2 path", multiple = FALSE)),
div(style="display:inline-block;vertical-align:top;width:180px;",
textInput("path_exiaria2_textin", NULL, ""))),
div(style="height:20px;vertical-aling:top;",
htmlOutput("path_exiaria2_errormess")),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
div(style="text-align:right;",
disabled(actionButton("link_aria2_button", strong("\u2000Ok"), icon=icon("check"))),
modalButton("\u2000Cancel", icon = icon("ban")))
)
)
)
} else {
div(
p("aria2 needs to be installed",
"To do it, install the package \"aria2\",",
"then repeat this check."),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
div(style="text-align:right;",
modalButton("\u2000Close", icon = icon("check")))
)
}
)
} else if (rv$check_aria2_isvalid) {
div(
align = "center",
p(style="text-align:center;font-size:500%;color:darkgreen;",
icon("check-circle")),
p("aria2 is correctly installed."),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
div(style="text-align:right;",
modalButton("\u2000Close", icon = icon("check")))
)
}
})
# check the aria2 path
observeEvent(input$path_newaria2_textin, {
path_newaria2_errormess <- path_check(
input$path_newaria2_textin,
mustbe_writable = TRUE,
mustbe_empty = FALSE
)
output$path_newaria2_errormess <- path_newaria2_errormess
if (TRUE %in% attr(path_newaria2_errormess, "isvalid")) {
enable("install_aria2_button")
} else {
disable("install_aria2_button")
}
})
shinyDirChoose(input, "path_newaria2_sel", roots = volumes)
observeEvent(input$path_newaria2_sel, {
path_newaria2_string <- parseDirPath(volumes, input$path_newaria2_sel)
updateTextInput(session, "path_newaria2_textin", value = path_newaria2_string)
})
observeEvent(input$path_exiaria2_textin, {
if (any(length(input$path_exiaria2_textin)==0, input$path_exiaria2_textin[1]=="")) {
output$path_exiaria2_errormess <- renderText("")
disable("link_aria2_button")
} else if (!file.exists(input$path_exiaria2_textin)) {
output$path_exiaria2_errormess <- renderUI(span(
style="color:red",
"\u2718 (the file does not exist)"
))
disable("link_aria2_button")
} else if (!grepl("^aria2c?\\.exe$", basename(input$path_exiaria2_textin))) {
output$path_exiaria2_errormess <- renderUI(span(
style="color:red",
"\u2718 (this is not aria2c.exe)"
))
disable("link_aria2_button")
} else {
output$path_exiaria2_errormess <- renderUI(span(
style="color:darkgreen",
"\u2714"
))
enable("link_aria2_button")
}
})
shinyFileChoose(input, "path_exiaria2_sel", roots = volumes)
observeEvent(input$path_exiaria2_sel, {
path_exiaria2_string <- parseFilePaths(volumes, input$path_exiaria2_sel)$datapath
updateTextInput(session, "path_exiaria2_textin", value = path_exiaria2_string)
})
# build the modalDialog
check_aria2_modal <- modalDialog(
title = "aria2 check",
size = "s",
uiOutput("check_aria2_message"),
easyClose = FALSE,
footer = NULL
)
# open the modaldialog when button is pressed
observeEvent(input$check_aria2, {
# update the check
rv$check_aria2_isvalid <- if (
!is.null(suppressWarnings(load_binpaths("aria2c")$aria2c))
) {
file.exists(load_binpaths()$aria2c)
} else {
FALSE
}
# open modaldialog
showModal(check_aria2_modal)
})
# install aria2
observeEvent(input$install_aria2_button, {
shinyjs::html(
"check_aria2_message",
as.character(div(
align="center",
p(style="text-align:center;font-size:500%;color:darkgrey;",
icon("cog", class = "fa-spin")),
p("Wait while aria2 is being installed...")
))
)
Sys.sleep(0.5)
check_aria2_outerr <- tryCatch(
install_aria2(input$path_newaria2_textin),
error = function(e) {print(e)}
)
# remove the text
if (is(check_aria2_outerr, "error")) {
shinyjs::html(
"check_aria2_message",
as.character(div(
align="center",
p(style="text-align:center;font-size:500%;color:red;",
icon("times-circle")),
p("Some errors occurred:"),
p(code(check_aria2_outerr)),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
div(style="text-align:right;",
modalButton("\u2000Close", icon = icon("check")))
))
)
rv$check_aria2_isvalid <- FALSE
} else {
shinyjs::html(
"check_aria2_message",
as.character(div(
align="center",
p(style="text-align:center;font-size:500%;color:darkgreen;",
icon("check-circle")),
p("aria2 was correctly installed."),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
div(style="text-align:right;",
modalButton("\u2000Close", icon = icon("check")))
))
)
rv$check_aria2_isvalid <- TRUE
}
})
# link an existing aria2
observeEvent(input$link_aria2_button, {
binpaths_content <- load_binpaths()
binpaths_content$aria2c <- normalize_path(input$path_exiaria2_textin)
writeLines(jsonlite::toJSON(binpaths_content, pretty=TRUE), attr(binpaths(), "path"))
rv$check_aria2_isvalid <- TRUE
removeModal()
})
#-- Check sen2cor --#
# build the icon of the check
observe({
input$check_sen2cor # redo when the button is pressed
rv$check_sen2cor_isvalid <- if (!is.null(binpaths()$sen2cor)) {
file.exists(binpaths()$sen2cor)
} else {FALSE}
})
output$check_sen2cor_isvalid <- renderText(rv$check_sen2cor_isvalid)
output$check_sen2cor_icon <- renderUI({
if (is.na(rv$check_sen2cor_isvalid)) {
""
} else if (rv$check_sen2cor_isvalid) {
span(style="color:darkgreen;", "\u2714")
} else {
span(style="color:red;", "\u2718")
}
})
outputOptions(output, "check_sen2cor_isvalid", suspendWhenHidden = FALSE)
output$check_sen2cor_message <- renderUI({
if (is.na(rv$check_sen2cor_isvalid)) {
""
} else if (rv$check_sen2cor_isvalid) {
div(
align = "center",
p(style="color:darkgreen;text-align:center;font-size:500%;",
icon("check-circle")),
p("Sen2Cor is correctly installed."),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
div(style="text-align:right;",
modalButton("\u2000Close", icon = icon("check")))
)
} else {
div(
align = "left",
p(style="color:red;text-align:center;font-size:500%;",
icon("times-circle")),
div(
style = "margin-bottom: 1em;",
p("Sen2Cor needs to be linked to sen2r, or downloaded if missing.")
),
radioButtons(
"sen2cor_link_or_install", NULL,
c("Install a new Sen2Cor environment" = "install",
"Set the path of an existing Sen2Cor" = "link"),
selected = "install"
),
conditionalPanel(
condition = "input.sen2cor_link_or_install == 'install'",
div(
p("Please provide the path of an empty directory ",
"in which installing it:"),
div(div(style="display:inline-block;vertical-align:top;width:50pt;",
shinyDirButton("path_newsen2cor_sel", "Select", "Specify directory in which installing Sen2Cor")),
div(style="display:inline-block;vertical-align:top;width:480px;",
textInput("path_newsen2cor_textin", NULL, normalize_path(
file.path(dirname(attr(binpaths(), "path")), "sen2cor"), mustWork = FALSE
)))),
div(style="height:20px;vertical-aling:top;",
htmlOutput("path_newsen2cor_errormess")),
radioButtons(
"sen2cor_version", "Sen2Cor version to be installed:",
c("Stable version (2.5.5)" = "2.5.5",
"Newer, lighter version (2.8.0)" = "2.8.0"),
selected = "2.5.5"
),
shiny::tags$small(em(p(
"Sen2Cor 2.8.0 is faster and makes use of less RAM, but",
"it only works for SAFE products version >= 14.2 and",
"some problems were encountered running it on Windows;",
"it is recommended to use Sen2Cor 2.5.5."
)))
)
),
conditionalPanel(
condition = "input.sen2cor_link_or_install == 'link'",
div(
p("Please provide the path of the directory ",
"in which Sen2Cor is currently installed:"),
div(div(style="display:inline-block;vertical-align:top;width:50pt;",
shinyDirButton("path_exisen2cor_sel", "Select", "Specify directory in which Sen2Cor is installed")),
div(style="display:inline-block;vertical-align:top;width:480px;",
textInput("path_exisen2cor_textin", NULL, normalize_path(
file.path(dirname(attr(binpaths(), "path")), "sen2cor"), mustWork = FALSE
)))),
div(style="height:20px;vertical-aling:top;",
htmlOutput("path_exisen2cor_errormess"))
)
),
# radioButtons(
# "sen2cor_use_dem", "Use DEM for topographic correction?",
# c("Yes (as done in ESA Hub Level-2 products)" = TRUE,
# "No (default Sen2Cor setting)" = FALSE,
# "Use existing choice (Sen2Cor reinstallation / link)" = NA),
# selected = TRUE, width = "100%"
# ),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
conditionalPanel(
condition = "input.sen2cor_link_or_install == 'install'",
div(style="text-align:right;",
disabled(actionButton("install_sen2cor_button", strong("\u2000Download"), icon=icon("download"))),
modalButton("\u2000Cancel", icon = icon("ban")))
),
conditionalPanel(
condition = "input.sen2cor_link_or_install == 'link'",
div(style="text-align:right;",
disabled(actionButton("link_sen2cor_button", strong("\u2000Ok"), icon=icon("check"))),
modalButton("\u2000Cancel", icon = icon("ban")))
)
)
}
})
# check the Sen2Cor paths
observeEvent(input$path_newsen2cor_textin, {
path_newsen2cor_errormess <- path_check(
input$path_newsen2cor_textin,
mustbe_writable = TRUE,
mustbe_empty = TRUE
)
output$path_newsen2cor_errormess <- path_newsen2cor_errormess
if (TRUE %in% attr(path_newsen2cor_errormess, "isvalid")) {
enable("install_sen2cor_button")
} else {
disable("install_sen2cor_button")
}
})
shinyDirChoose(input, "path_newsen2cor_sel", roots = volumes)
observeEvent(input$path_newsen2cor_sel, {
path_newsen2cor_string <- parseDirPath(volumes, input$path_newsen2cor_sel)
updateTextInput(session, "path_newsen2cor_textin", value = path_newsen2cor_string)
})
observeEvent(input$path_exisen2cor_textin, {
path_exisen2cor_errormess <- path_check(
input$path_exisen2cor_textin,
mustbe_writable = FALSE,
mustbe_empty = FALSE
)
if (TRUE %in% attr(path_exisen2cor_errormess, "isvalid")) {
if (.sen2cor_exists(input$path_exisen2cor_textin)) {
output$path_exisen2cor_errormess <- path_exisen2cor_errormess
enable("link_sen2cor_button")
} else {
output$path_exisen2cor_errormess <- renderUI(span(
style="color:red",
"\u2718 (Sen2Cor was not found here)"
))
disable("link_sen2cor_button")
}
} else {
output$path_exisen2cor_errormess <- path_exisen2cor_errormess
disable("link_sen2cor_button")
}
})
shinyDirChoose(input, "path_exisen2cor_sel", roots = volumes)
observeEvent(input$path_exisen2cor_sel, {
path_exisen2cor_string <- parseDirPath(volumes, input$path_exisen2cor_sel)
updateTextInput(session, "path_exisen2cor_textin", value = path_exisen2cor_string)
})
# build the modalDialog
check_sen2cor_modal <- modalDialog(
title = "Sen2Cor check",
size = "m",
uiOutput("check_sen2cor_message"),
easyClose = FALSE,
footer = NULL
)
# open the modaldialog when button is pressed
observeEvent(input$check_sen2cor, {
# open the dialog
showModal(check_sen2cor_modal)
})
# install sen2cor
observeEvent(input$install_sen2cor_button, {
# create the text to show in the modaldialog
shinyjs::html(
"check_sen2cor_message",
as.character(div(
align="center",
p(style="text-align:center;font-size:500%;color:darkgrey;",
icon("cog", class = "fa-spin")),
p("Wait while Sen2Cor is being installed...")
))
)
check_sen2cor_outmess <- capture.output(
check_sen2cor_outerr <- tryCatch(
.install_sen2cor(
input$path_newsen2cor_textin,
version = input$sen2cor_version,
interactive = FALSE
),
error = function(e) {print(e)}
),
type = "message"
)
# remove the text
if (is(check_sen2cor_outerr, "error")) {
rv$check_sen2cor_isvalid <- FALSE
shinyjs::html(
"check_sen2cor_message",
as.character(div(
p(code(check_sen2cor_outmess)),
p(code(check_sen2cor_outerr)),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
div(style="text-align:right;",
modalButton("\u2000Close", icon = icon("check")))
))
)
} else {
rv$check_sen2cor_isvalid <- TRUE
shinyjs::html(
"check_sen2cor_message",
as.character(div(
align="center",
p(style="text-align:center;font-size:500%;color:darkgreen;",
icon("check-circle")),
p("Sen2Cor was correctly installed."),
hr(style="margin-top: 0.75em; margin-bottom: 0.75em;"),
div(style="text-align:right;",
modalButton("\u2000Close", icon = icon("check")))
))
)
}
})
# link an existing sen2cor
observeEvent(input$link_sen2cor_button, {
link_sen2cor(input$path_exisen2cor_textin)
rv$check_sen2cor_isvalid <- TRUE
removeModal()
})
# ##-- Footer buttons --##
# observe({
# rv$check_all_isvalid <- all(c(
# rv$check_gdal_isvalid, rv$check_aria2_isvalid,
# rv$check_sen2cor_isvalid
# ))
# })
output$footer_buttons <- renderUI({
div(
style = "vertical-align:center;text-align:right;",
# if (rv$check_all_isvalid) {
# span(
# style = "display:inline-block;",
# "All the dependencies are satisfied, you can safely use the library.\u2000"
# )
# # actionButton("close_gui", "\u2000Close", icon = icon("check"), class = "darkbutton")
# },
actionButton(
"close_gui", "\u2000Close",
# icon = icon(ifelse(rv$check_all_isvalid, "check", "exclamation-triangle")),
icon = icon("check"),
class = "darkbutton"
)
)
})
# Close the connection when button is pressed
observeEvent(input$close_gui, {
# if (!rv$check_all_isvalid) {
# confirmSweetAlert(
# session = session, inputId = "confirm_close", type = "warning",
# title = "Closing the GUI?",
# text = paste0(
# "Are you sure do you want to quit? ",
# "Running the package with unsatisfied ",
# "dependencies can lead to errors."
# ),
# danger_mode = TRUE, btn_labels = c("Cancel", "Close window")
# )
# } else {
shinyjs::js$closeWindow()
stopApp()
# }
})
observeEvent(input$confirm_close, {
if (input$confirm_close) {
shinyjs::js$closeWindow()
stopApp()
}
})
# Close the connection when window is closed
session$onSessionEnded(function() {
stopApp()
})
}
settings.shiny <- shinyApp(
ui = settings.ui, server = settings.server,
options = list(width="400px", height="400px")
)
# run
if (interactive()) {
options(device.ask.default = FALSE)
return(runApp(settings.shiny))
} else {
stop("The function must be run from an interactive R session.")
}
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.