test_that("install_pkg_cli_apps installs launchers for matching scripts", { Sys.setenv("RAPP_NO_MODIFY_PATH" = "1") on.exit(Sys.unsetenv("RAPP_NO_MODIFY_PATH"), add = TRUE) pkg <- "rappTestBasic" fake <- setup_fake_rapp_package(tempdir(), "-install-basic", package = pkg) on.exit(unlink(fake[["lib"]], recursive = TRUE), add = TRUE) app_path <- file.path(fake[["exec"]], "hello.R") writeLines( c( "#!/usr/bin/env Rapp", "print('hello, world!')" ), app_path ) # Should be ignored because first line lacks the keyword. writeLines( c( "not a launcher candidate", "print('skip me')" ), file.path(fake[["exec"]], "skip.R") ) destdir <- tempfile("rapp-bin-basic") on.exit(unlink(destdir, recursive = TRUE), add = TRUE) expect_false(dir.exists(destdir)) messages <- character() created <- withCallingHandlers( install_pkg_cli_apps(pkg, destdir = destdir, lib.loc = fake[["lib"]]), message = function(m) { messages <<- c(messages, conditionMessage(m)) invokeRestart("muffleMessage") } ) expect_true(any(grepl("^created:", messages))) expect_true(dir.exists(destdir)) expected_launcher <- if (is_windows()) { path(destdir, "hello.bat") } else { path(destdir, "hello") } expect_same_path(created, expected_launcher) expect_same_path( path(list.files(destdir, full.names = TRUE)), expected_launcher ) lines <- readLines(expected_launcher) if (is_windows()) { expect_identical(lines[[1]], "@echo off") expect_match( lines[[2]], sprintf( "^:: Generated by `Rapp::install_pkg_cli_apps\\(package = \"%s\"\\)`\\. Do not edit by hand\\.$", pkg ) ) } else { expect_identical(lines[[1]], "#!/bin/sh") expect_match( lines[[2]], sprintf( "^# Generated by `Rapp::install_pkg_cli_apps\\(package = \"%s\"\\)`\\. Do not edit by hand\\.$", pkg ) ) } expect_true(any(grepl("Rapp::run()", lines, fixed = TRUE))) expect_true(any(grepl("hello.R", lines, fixed = TRUE))) }) test_that("install_pkg_cli_apps installs launchers for conventional Rscript apps", { Sys.setenv("RAPP_NO_MODIFY_PATH" = "1") on.exit(Sys.unsetenv("RAPP_NO_MODIFY_PATH"), add = TRUE) pkg <- "rappTestRscript" fake <- setup_fake_rapp_package(tempdir(), "-install-rscript", package = pkg) on.exit(unlink(fake[["lib"]], recursive = TRUE), add = TRUE) app_path <- file.path(fake[["exec"]], "plain.R") writeLines( c( "#!/usr/bin/env Rscript", "cat('plain cli\\n')" ), app_path ) destdir <- tempfile("rapp-bin-rscript") on.exit(unlink(destdir, recursive = TRUE), add = TRUE) messages <- character() created <- withCallingHandlers( install_pkg_cli_apps(pkg, destdir = destdir, lib.loc = fake[["lib"]]), message = function(m) { messages <<- c(messages, conditionMessage(m)) invokeRestart("muffleMessage") } ) expect_true(any(grepl("^created:", messages))) expected_launcher <- if (is_windows()) { path(destdir, "plain.bat") } else { path(destdir, "plain") } expect_same_path(created, expected_launcher) lines <- readLines(expected_launcher) if (is_windows()) { expect_identical(lines[[1]], "@echo off") expect_match( lines[[2]], sprintf( "^:: Generated by `Rapp::install_pkg_cli_apps\\(package = \"%s\"\\)`\\. Do not edit by hand\\.$", pkg ) ) expect_true(grepl("%\\*$", lines[[length(lines)]])) } else { expect_identical(lines[[1]], "#!/bin/sh") expect_match( lines[[2]], sprintf( "^# Generated by `Rapp::install_pkg_cli_apps\\(package = \"%s\"\\)`\\. Do not edit by hand\\.$", pkg ) ) expect_true(grepl("\"\\$@\"$", lines[[length(lines)]])) } expect_true(any(grepl("Rscript", lines, fixed = TRUE))) expect_true(any(grepl("plain.R", lines, fixed = TRUE))) expect_false(any(grepl("Rapp::run()", lines, fixed = TRUE))) }) test_that("non-Rapp executables respect overwrite flag", { Sys.setenv("RAPP_NO_MODIFY_PATH" = "1") on.exit(Sys.unsetenv("RAPP_NO_MODIFY_PATH"), add = TRUE) pkg <- "rappTestOverwrite" fake <- setup_fake_rapp_package( tempdir(), "-install-overwrite", package = pkg ) on.exit(unlink(fake[["lib"]], recursive = TRUE), add = TRUE) app_path <- file.path(fake[["exec"]], "clash.R") writeLines(c("#!/usr/bin/env Rapp", "print('conflict')"), app_path) destdir <- tempfile("rapp-bin-overwrite") dir.create(destdir, recursive = TRUE) on.exit(unlink(destdir, recursive = TRUE), add = TRUE) target <- if (is_windows()) { path(destdir, "clash.bat") } else { path(destdir, "clash") } custom_launcher <- if (is_windows()) { c("@echo off", "custom launcher") } else { c("#!/bin/sh", "custom launcher") } writeLines(custom_launcher, target) Sys.chmod(target, mode = "0755") expect_warning( created <- install_pkg_cli_apps( pkg, destdir = destdir, lib.loc = fake[["lib"]], overwrite = FALSE ), "Skipping existing executable" ) expect_length(created, 0) expect_identical(readLines(target), custom_launcher) messages <- character() created <- withCallingHandlers( install_pkg_cli_apps( pkg, destdir = destdir, lib.loc = fake[["lib"]], overwrite = TRUE ), message = function(m) { messages <<- c(messages, conditionMessage(m)) invokeRestart("muffleMessage") } ) expect_true(any(grepl("^created:", messages))) expect_same_path(created, target) expect_true(any(grepl( "Generated by `Rapp::install_pkg_cli_apps", readLines(target), fixed = TRUE ))) }) test_that("front matter customises launcher options", { pkg <- "rappTestFront" fake <- setup_fake_rapp_package( tempdir(), "-install-frontmatter", package = pkg ) on.exit(unlink(fake[["lib"]], recursive = TRUE), add = TRUE) app_path <- file.path(fake[["exec"]], "opts.R") writeLines( c( "#!/usr/bin/env -S Rscript -e 'Rapp::run()'", "#| launcher:", "#| vanilla: true", "#| 'no-environ': true", "#| 'no-site-file': true", "#| 'no-init-file': true", "#| restore: true", "#| save: true", "#| verbose: true", "#| default_packages: [stats]", "print('options test')" ), app_path ) destdir <- tempfile("rapp-bin-frontmatter") on.exit(unlink(destdir, recursive = TRUE), add = TRUE) messages <- character() created <- withCallingHandlers( install_pkg_cli_apps(pkg, destdir = destdir, lib.loc = fake[["lib"]]), message = function(m) { messages <<- c(messages, conditionMessage(m)) invokeRestart("muffleMessage") } ) expect_true(any(grepl("^created:", messages))) expected_launcher <- if (is_windows()) { path(destdir, "opts.bat") } else { path(destdir, "opts") } expect_same_path(created, expected_launcher) lines <- readLines(expected_launcher) exec_line <- lines[length(lines)] expect_true(grepl("--vanilla", exec_line, fixed = TRUE)) expect_true(grepl("--no-environ", exec_line, fixed = TRUE)) expect_true(grepl("--no-site-file", exec_line, fixed = TRUE)) expect_true(grepl("--no-init-file", exec_line, fixed = TRUE)) expect_true(grepl("--restore", exec_line, fixed = TRUE)) expect_true(grepl("--save", exec_line, fixed = TRUE)) expect_true(grepl("--verbose", exec_line, fixed = TRUE)) expect_true(grepl("--default-packages=stats", exec_line, fixed = TRUE)) expect_false(grepl(paste0("base,", pkg), exec_line, fixed = TRUE)) expect_true(grepl("Rapp::run()", exec_line, fixed = TRUE)) }) test_that("install_pkg_cli_apps prunes orphaned launchers", { Sys.setenv("RAPP_NO_MODIFY_PATH" = "1") on.exit(Sys.unsetenv("RAPP_NO_MODIFY_PATH"), add = TRUE) pkg <- "rappTestPrune" fake <- setup_fake_rapp_package(tempdir(), "-install-prune", package = pkg) on.exit(unlink(fake[["lib"]], recursive = TRUE), add = TRUE) keep_path <- path(fake[["exec"]], "keep.R") drop_path <- path(fake[["exec"]], "drop.R") writeLines(c("#!/usr/bin/env Rapp", "print('keep')"), keep_path) writeLines(c("#!/usr/bin/env Rapp", "print('drop')"), drop_path) destdir <- tempfile("rapp-bin-prune") on.exit(unlink(destdir, recursive = TRUE), add = TRUE) messages <- character() first_created <- withCallingHandlers( install_pkg_cli_apps(pkg, destdir = destdir, lib.loc = fake[["lib"]]), message = function(m) { messages <<- c(messages, conditionMessage(m)) invokeRestart("muffleMessage") } ) expect_true(sum(grepl("^created:", messages)) == 2L) keep_launcher <- if (is_windows()) { path(destdir, "keep.bat") } else { path(destdir, "keep") } drop_launcher <- if (is_windows()) { path(destdir, "drop.bat") } else { path(destdir, "drop") } expect_same_paths_set(first_created, c(keep_launcher, drop_launcher)) expect_true(all(file.exists(c(keep_launcher, drop_launcher)))) unlink(drop_path) messages <- character() second_created <- withCallingHandlers( install_pkg_cli_apps(pkg, destdir = destdir, lib.loc = fake[["lib"]]), message = function(m) { messages <<- c(messages, conditionMessage(m)) invokeRestart("muffleMessage") } ) messages <- trimws(messages) expect_true(any(grepl("^created: ", messages))) expect_true(any(paste0("deleted: ", drop_launcher) %in% messages)) expect_same_path(second_created, keep_launcher) expect_true(file.exists(keep_launcher)) expect_false(file.exists(drop_launcher)) })