Skip to content

Commit 90c332f

Browse files
committed
windows fixes
1 parent 5cbab9f commit 90c332f

2 files changed

Lines changed: 111 additions & 27 deletions

File tree

R/install.R

Lines changed: 77 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ install_pkg_cli_apps <- function(
5959
dir.create(destdir, recursive = TRUE) ||
6060
stop("Failed to create directory: ", destdir)
6161

62+
if (is_windows()) {
63+
ensure_path_windows(destdir)
64+
}
65+
6266
existing <- list_existing_rapp_launchers(destdir)
6367

6468
names(package) <- package
@@ -120,38 +124,40 @@ list_package_apps <- function(package, lib.loc = NULL) {
120124

121125

122126
rapp_install_dir <- function() {
123-
env <- Sys.getenv("RAPP_INSTALL_DIR", NA_character_)
124-
if (!is.na(env) && nzchar(env)) {
125-
return(normalizePath(env, mustWork = FALSE))
126-
}
127-
128-
switch(
129-
.Platform$OS.type,
130-
windows = {
131-
base <- Sys.getenv("LOCALAPPDATA", "") # this should probably resolve to $HOME/.local/bin
132-
base <- if (nzchar(base)) {
133-
normalizePath(base, mustWork = FALSE)
134-
} else {
135-
normalizePath(file.path("~", "AppData", "Local"), mustWork = FALSE)
127+
getenv <- function(x) Sys.getenv(x, NA_character_)
128+
is_set <- function(x) !is.na(x) && nzchar(x)
129+
130+
path <- if (is_set(p <- getenv("RAPP_BIN_DIR"))) {
131+
p
132+
} else if (is_set(p <- getenv("XDG_BIN_HOME"))) {
133+
p
134+
} else if (is_set(p <- getenv("XDG_DATA_HOME"))) {
135+
file.path(dirname(p), "bin")
136+
} else {
137+
switch(
138+
.Platform$OS.type,
139+
unix = "~/.local/bin",
140+
windows = {
141+
base <- if (is_set(p <- getenv("LOCALAPPDATA"))) {
142+
p
143+
} else if (is_set(p <- getenv("USERPROFILE"))) {
144+
file.path(p, "AppData", "Local")
145+
} else {
146+
path.expand("~/AppData/Local")
147+
}
148+
file.path(base, "Programs", "R", "Rapp", "bin")
136149
}
137-
normalizePath(
138-
file.path(base, "Programs", "Rapp", "bin"),
139-
mustWork = FALSE
140-
)
141-
},
142-
unix = {
143-
xdg <- Sys.getenv("XDG_BIN_HOME", "~/.local/bin")
144-
normalizePath(xdg, mustWork = FALSE)
145-
}
146-
)
150+
)
151+
}
152+
normalizePath(path, mustWork = FALSE)
147153
}
148154

149155

150156
launcher_path <- function(app_path, destdir) {
151157
name <- sub("\\.[rR]$", "", basename(app_path))
152158
switch(
153159
.Platform$OS.type,
154-
windows = file.path(destdir, paste0(name, ".bat")),
160+
windows = file.path(destdir, paste0(name, ".bat"), fsep = "\\"),
155161
unix = file.path(destdir, name)
156162
)
157163
}
@@ -223,7 +229,7 @@ launcher_contents <- function(app_path, package) {
223229
install_rapp_launcher <- function(destdir) {
224230
target <- switch(
225231
.Platform$OS.type,
226-
windows = file.path(destdir, "Rapp.bat"),
232+
windows = file.path(destdir, "Rapp.bat", fsep = "\\"),
227233
unix = file.path(destdir, "Rapp")
228234
)
229235

@@ -239,15 +245,15 @@ install_rapp_launcher <- function(destdir) {
239245
"@echo off",
240246
"setlocal",
241247
sprintf(
242-
r"("%s/Rscript.exe" --default-packages=base -e Rapp::run() %%*)",
248+
r"("%s/Rscript.exe" -e Rapp::run() %%*)",
243249
R.home("bin")
244250
)
245251
),
246252
unix = c(
247253
"#!/bin/sh",
248254
paste("#", sentinel),
249255
sprintf(
250-
r"(exec %s/Rscript --default-packages=base -e 'Rapp::run()' "$@")",
256+
r"(exec %s/Rscript -e 'Rapp::run()' "$@")",
251257
R.home("bin")
252258
)
253259
)
@@ -293,3 +299,47 @@ get_rapp_launcher_package <- function(path) {
293299
)
294300
if (identical(pkg, lines[2])) NA_character_ else pkg
295301
}
302+
303+
304+
# Ensure a directory is first on the user PATH (Windows)
305+
ensure_path_windows <- function(destdir = rapp_install_dir()) {
306+
stopifnot(.Platform$OS.type == "windows")
307+
destdir <- normalizePath(destdir, winslash = "\\", mustWork = TRUE)
308+
309+
# Check if we're already on PATH. If we are, do nothing
310+
# Read current PATH from HKCU\Environment
311+
path <- get_env_win_registry("Path")
312+
path <- strsplit(path, ";", fixed = TRUE)[[1L]]
313+
path <- path[nzchar(path)]
314+
path <- unique(path)
315+
316+
path_norm <- function(x) tolower(normalizePath(x, mustWork = FALSE))
317+
present <- path_norm(destdir) %in% path_norm(path)
318+
if (present) {
319+
return(FALSE)
320+
}
321+
322+
# We are not on the PATH yet, we have to add it
323+
# Pass the new path entry via envvar to avoid quoting and encoding shenanigans
324+
# also, propogate the new updated PATH from the registry to this R session
325+
old <- Sys.getenv("RAPP_NEW_PATH_ENTRY", NA_character_)
326+
Sys.setenv("RAPP_NEW_PATH_ENTRY" = destdir)
327+
on.exit({
328+
if (is.na(old)) {
329+
Sys.unsetenv("RAPP_NEW_PATH_ENTRY")
330+
} else {
331+
Sys.setenv("RAPP_NEW_PATH_ENTRY" = old)
332+
}
333+
Sys.setenv("PATH" = get_env_win_registry("Path"))
334+
})
335+
336+
script <- shQuote(utils::shortPathName(
337+
system.file("add-path-entry.ps1", package = "Rapp")
338+
))
339+
args <- c("-NoProfile", "-ExecutionPolicy", "Bypass", "-File", script)
340+
system2("powershell", args)
341+
}
342+
343+
get_env_win_registry <- function(name) {
344+
utils::readRegistry("Environment", hive = "HCU", view = "default")[[name]]
345+
}

inst/add-path-entry.ps1

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
param([string]$NewPathEntry)
2+
3+
$RegistryPath = 'registry::HKEY_CURRENT_USER\Environment'
4+
5+
# Prefer env var from caller; fall back to param
6+
$NewPathEntry = if ($env:RAPP_NEW_PATH_ENTRY) { $env:RAPP_NEW_PATH_ENTRY } elseif ($NewPathEntry) { $NewPathEntry } else {
7+
Write-Error "Provide RAPP_BIN_DIR or -NewPathEntry."
8+
exit 2
9+
}
10+
11+
Write-Verbose "Adding $NewPathEntry to your user-level PATH"
12+
13+
# Read unexpanded PATH components
14+
$PathEntries = (Get-Item -LiteralPath $RegistryPath).GetValue(
15+
'Path', '', 'DoNotExpandEnvironmentNames') -split ';' -ne ''
16+
17+
if ($NewPathEntry -in $PathEntries) {
18+
Write-Verbose "Install directory $NewPathEntry already on PATH!"
19+
exit 1
20+
}
21+
22+
# Prepend to PATH
23+
$NewPath = (,$NewPathEntry + $PathEntries) -join ';'
24+
25+
# Update registry as REG_EXPAND_SZ
26+
Set-ItemProperty -Type ExpandString -LiteralPath $RegistryPath Path -Value $NewPath
27+
28+
# Broadcast WM_SETTINGCHANGE via dummy env var toggle
29+
$DummyName = 'rapp-' + [guid]::NewGuid().ToString()
30+
[Environment]::SetEnvironmentVariable($DummyName, 'rapp-dummy', 'User')
31+
[Environment]::SetEnvironmentVariable($DummyName, $null, 'User')
32+
33+
Write-Output "Added $NewPathEntry to your user-level PATH"
34+
exit 0

0 commit comments

Comments
 (0)