Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ URL: https://github.com/r-lib/Rapp
BugReports: https://github.com/r-lib/Rapp/issues
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.3
Suggests:
testthat (>= 3.0.0),
withr
Expand All @@ -22,3 +21,4 @@ Config/testthat/parallel: true
Config/testthat/start-first: help-snapshots, basics
Imports:
yaml12
Config/roxygen2/version: 8.0.0
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@

## Bug fixes

- On macOS, `install_pkg_cli_apps()` now adds the default `~/.local/bin`
install directory to the user's zsh profile when it is not already
on `PATH`, respecting `ZDOTDIR` and warning rather than failing if
the profile cannot be updated (#35).
- Launcher front matter now accepts documented kebab-case option names
such as `default-packages`. Installation docs now clarify that package
apps are discovered as `exec/*.R`, installed without the `.R` extension
Expand Down
131 changes: 128 additions & 3 deletions R/install.R
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,13 @@
#' - Windows: `%LOCALAPPDATA%\Programs\R\Rapp\bin`
#'
#' On Windows, the resolved `destdir` is explicitly added to `PATH` (it
#' generally is not by default). To disable adding it to the `PATH`, set envvar
#' `RAPP_NO_MODIFY_PATH=1`.
#' generally is not by default). On macOS, when the default `~/.local/bin`
#' destination is not already on `PATH`, it is added to `~/.zprofile`, or
#' `$ZDOTDIR/.zprofile` when `ZDOTDIR` is set. If the profile cannot be
#' updated, a warning is emitted and installation continues. To disable adding
#' it to the `PATH`, set envvar `RAPP_NO_MODIFY_PATH=1`.
#'
#' On macOS or Linux, `~/.local/bin` is typically already on `PATH` if it
#' On Linux, `~/.local/bin` is typically already on `PATH` if it
#' exists. Note: some shells add `~/.local/bin` to `PATH` only if it exists at
#' login. If `install_pkg_cli_apps()` created the directory, you may need to
#' restart the shell for the new apps to be found on `PATH`.
Expand Down Expand Up @@ -89,6 +92,8 @@ install_pkg_cli_apps <- function(

if (is_windows()) {
ensure_path_windows(destdir)
} else if (is_macos()) {
ensure_path_macos(destdir)
}

# existing Rapp launchers we're either overwriting or deleting
Expand Down Expand Up @@ -518,6 +523,126 @@ get_env_win_registry <- function(name) {
utils::readRegistry("Environment", hive = "HCU", view = "default")[[name]]
}

ensure_path_macos <- function(destdir = rapp_install_dir()) {
if (Sys.getenv("RAPP_NO_MODIFY_PATH") != "") {
return(FALSE)
}
stopifnot(is_macos())

destdir <- normalizePath(destdir, mustWork = TRUE)
if (!identical(destdir, macos_default_install_dir())) {
return(FALSE)
}
if (path_has_dir(destdir)) {
return(FALSE)
}

zprofile <- macos_zprofile()
zprofile_display <- macos_zprofile_display(zprofile)
lines <- macos_path_lines()

if (profile_has_lines(zprofile, lines)) {
warning(
"~/.local/bin PATH setup is already present in ",
zprofile_display,
", ",
"but ~/.local/bin is still not on PATH.\n",
"Restart your shell, or run:\n\n",
" source ", zprofile_display,
call. = FALSE
)
} else if (write_macos_path_lines(zprofile, lines, zprofile_display)) {
message(
"Added ~/.local/bin to PATH in ", zprofile_display, ".\n",
"Restart your shell, or run:\n\n",
" source ", zprofile_display
)
}

Sys.setenv(PATH = paste(destdir, Sys.getenv("PATH"), sep = .Platform$path.sep))
TRUE
}

macos_default_install_dir <- function() {
normalizePath(file.path(path.expand("~"), ".local", "bin"), mustWork = FALSE)
}

macos_zprofile <- function() {
zdotdir <- Sys.getenv("ZDOTDIR")
if (!nzchar(zdotdir)) {
zdotdir <- path.expand("~")
}
path(zdotdir, ".zprofile")
}

macos_zprofile_display <- function(zprofile) {
if (identical(path(zprofile), path(path.expand("~"), ".zprofile"))) {
"~/.zprofile"
} else {
zprofile
}
}

macos_path_lines <- function() {
c(
'case ":$PATH:" in',
' *:"$HOME/.local/bin":*) ;;',
' *) export PATH="$HOME/.local/bin:$PATH" ;;',
"esac"
)
}

profile_has_lines <- function(profile, lines) {
if (!file.exists(profile)) {
return(FALSE)
}
profile <- tryCatch(
paste(readLines(profile, warn = FALSE), collapse = "\n"),
error = function(e) "",
warning = function(w) ""
)
grepl(paste(lines, collapse = "\n"), profile, fixed = TRUE)
}

write_macos_path_lines <- function(profile, lines, profile_display) {
tryCatch(
{
suppressWarnings(cat(
paste0(c("", lines), collapse = "\n"),
"\n",
file = profile,
append = TRUE,
sep = ""
))
TRUE
},
error = function(e) {
warning(
"Could not add ~/.local/bin to PATH in ",
profile_display,
": ",
conditionMessage(e),
call. = FALSE
)
FALSE
}
)
}

path_has_dir <- function(dir, env_path = Sys.getenv("PATH")) {
normalizePath(dir, mustWork = FALSE) %in% path_entries(env_path)
}

path_entries <- function(env_path = Sys.getenv("PATH")) {
entries <- strsplit(env_path, .Platform$path.sep, fixed = TRUE)[[1L]]
entries <- entries[nzchar(entries)]
normalizePath(entries, mustWork = FALSE)
}

is_macos <- function() {
identical(Sys.info()[["sysname"]], "Darwin")
}

path <- function(...) {
normalizePath(file.path(...), mustWork = FALSE)
}
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -425,10 +425,13 @@ App launchers are written to `destdir`, which defaults to the first
available location from `RAPP_BIN_DIR`, `XDG_BIN_HOME`,
`XDG_DATA_HOME/../bin`, or the default location, `~/.local/bin` on macOS
and Linux and `%LOCALAPPDATA%\Programs\R\Rapp\bin` on Windows. On
Windows the directory is automatically added to `PATH`; on macOS and
Linux the directory generally is already present on `PATH` (you may need
to restart your shell if the Rapp installer created the directory). Use
the `destdir` argument if you prefer an alternate location.
Windows the directory is automatically added to `PATH`; on macOS, the
default `~/.local/bin` directory is added to `~/.zprofile` when needed
(`$ZDOTDIR/.zprofile` when `ZDOTDIR` is set). If that profile cannot be
updated, Rapp warns and continues installing launchers. On Linux the
directory generally is already present on `PATH` (you may need to log
out and back in if the Rapp installer created the directory). Use the
`destdir` argument if you prefer an alternate location.

Use `#| launcher:` front matter to customize the installed launcher. For
example, `name` changes the installed command name, and `vanilla`,
Expand Down
9 changes: 6 additions & 3 deletions man/install_pkg_cli_apps.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading