Skip to content

Commit da69794

Browse files
committed
Use xml2
devtools has an indirect dependency on xml2 already: pak::pkg_deps_explain("devtools", "xml2") #> devtools -> pkgdown -> xml2 #> devtools -> roxygen2 -> xml2 #> devtools -> urlchecker -> xml2
1 parent 4e3faeb commit da69794

2 files changed

Lines changed: 37 additions & 27 deletions

File tree

DESCRIPTION

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ Suggests:
5454
remotes (>= 2.5.0),
5555
rmarkdown (>= 2.14),
5656
rstudioapi (>= 0.13),
57-
spelling (>= 2.2)
57+
spelling (>= 2.2),
58+
xml2
5859
VignetteBuilder: knitr, quarto
5960
Config/Needs/website: tidyverse/tidytemplate
6061
Config/testthat/edition: 3

R/check-win.R

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -237,42 +237,51 @@ upload_ftp <- function(file, url, verbose = FALSE) {
237237
curl::curl_fetch_memory(url, handle = h)
238238
}
239239

240-
extract_hidden_fields <- function(html_text) {
241-
extract_value <- function(name) {
242-
pattern <- sprintf('name="%s"[^>]*value="([^"]+)"', name)
243-
match <- regexec(pattern, html_text)
244-
result <- regmatches(html_text, match)
245-
if (length(result[[1]]) >= 2) result[[1]][2] else NA_character_
240+
parse_winbuilder_form <- function(url, version) {
241+
req <- httr2::request(url)
242+
resp <- httr2::req_perform(req)
243+
html <- xml2::read_html(httr2::resp_body_string(resp))
244+
245+
# Extract hidden fields shared by the whole form
246+
hidden_nodes <- xml2::xml_find_all(html, ".//input[@type='hidden']")
247+
hidden <- as.list(xml2::xml_attr(hidden_nodes, "value"))
248+
names(hidden) <- xml2::xml_attr(hidden_nodes, "name")
249+
250+
# Find the <h2> heading for the requested version, then grab the file
251+
# input and submit button from the <div> that follows it
252+
headings <- xml2::xml_find_all(html, ".//h2")
253+
heading_texts <- xml2::xml_text(headings)
254+
idx <- match(version, heading_texts)
255+
if (is.na(idx)) {
256+
cli::cli_abort(
257+
"Could not find {.val {version}} section in the WinBuilder form."
258+
)
246259
}
247260

248-
list(
249-
`__VIEWSTATE` = extract_value("__VIEWSTATE"),
250-
`__VIEWSTATEGENERATOR` = extract_value("__VIEWSTATEGENERATOR"),
251-
`__EVENTVALIDATION` = extract_value("__EVENTVALIDATION")
261+
section <- xml2::xml_find_first(headings[[idx]], "following-sibling::div")
262+
file_field <- xml2::xml_attr(
263+
xml2::xml_find_first(section, ".//input[@type='file']"),
264+
"name"
252265
)
266+
button_field <- xml2::xml_attr(
267+
xml2::xml_find_first(section, ".//input[@type='submit']"),
268+
"name"
269+
)
270+
271+
list(hidden = hidden, file_field = file_field, button_field = button_field)
253272
}
254273

255274
upload_webform <- function(file, version) {
256-
check_installed("httr2")
275+
check_installed(c("httr2", "xml2"))
257276

258277
upload_url <- "https://win-builder.r-project.org/upload.aspx"
259-
req <- httr2::request(upload_url)
260-
resp <- httr2::req_perform(req)
261-
html_text <- httr2::resp_body_string(resp)
262-
263-
field_map <- list(
264-
"R-release" = list(file = "FileUpload1", button = "Button1"),
265-
"R-devel" = list(file = "FileUpload2", button = "Button2"),
266-
"R-oldrelease" = list(file = "FileUpload3", button = "Button3")
267-
)
268-
269-
fields <- field_map[[version]]
278+
form <- parse_winbuilder_form(upload_url, version)
270279

271-
hidden <- extract_hidden_fields(html_text)
272-
hidden[[fields$file]] <- curl::form_file(file)
273-
hidden[[fields$button]] <- "Upload File"
280+
body <- form$hidden
281+
body[[form$file_field]] <- curl::form_file(file)
282+
body[[form$button_field]] <- "Upload File"
274283

275284
req <- httr2::request(upload_url)
276-
req <- httr2::req_body_multipart(req, !!!hidden)
285+
req <- httr2::req_body_multipart(req, !!!body)
277286
httr2::req_perform(req)
278287
}

0 commit comments

Comments
 (0)