Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor cargo-processx functions #397

Merged
merged 22 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from 11 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
55 changes: 24 additions & 31 deletions R/clean.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,19 @@
#' (found by default at `pkg_root/src/rust/target/`).
#' Useful when Rust code should be recompiled from scratch.
#' @param path \[ string \] Path to the package root.
#' @param echo logical scalar, should cargo command and outputs be printed to
#' console (default is TRUE)
#'
#' @export
clean <- function(path = ".") {
#'
#' @examples
#' \dontrun{
#' clean()
#' }
clean <- function(path = ".", echo = TRUE) {
check_string(path, class = "rextendr_error")
check_bool(echo, class = "rextendr_error")

root <- rprojroot::find_package_root_file(path = path)

rust_folder <- normalizePath(
Expand All @@ -15,7 +26,7 @@ clean <- function(path = ".") {
mustWork = FALSE
)

toml_path <- normalizePath(
manifest_path <- normalizePath(
file.path(rust_folder, "Cargo.toml"),
winslash = "/",
mustWork = FALSE
Expand All @@ -28,52 +39,34 @@ clean <- function(path = ".") {
mustWork = FALSE
)

if (!file.exists(toml_path)) {
if (!file.exists(manifest_path)) {
cli::cli_abort(c(
"Unable to clean binaries.",
"!" = "{.file Cargo.toml} not found in {.path {rust_folder}}.",
class = "rextendr_error"
))
}

cargo_envvars <- get_cargo_envvars()

args <- c(
"clean",
glue("--manifest-path={toml_path}"),
glue("--target-dir={target_dir}"),
glue::glue("--manifest-path={manifest_path}"),
glue::glue("--target-dir={target_dir}"),
if (tty_has_colors()) {
"--color=always"
} else {
"--color=never"
},
"--quiet"
JosiahParry marked this conversation as resolved.
Show resolved Hide resolved
}
)
exec_result <- processx::run(

processx::run(
command = "cargo",
args = args,
echo_cmd = FALSE,
windows_verbatim_args = FALSE,
stderr = "|",
stdout = "|",
error_on_status = FALSE,
env = cargo_envvars
error_on_status = TRUE,
wd = rust_folder,
echo_cmd = echo,
echo = echo,
env = get_cargo_envvars()
)

if (!isTRUE(exec_result$status == 0)) {
JosiahParry marked this conversation as resolved.
Show resolved Hide resolved
if (!tty_has_colors()) {
err_msg <- cli::ansi_strip(exec_result$stderr)
} else {
err_msg <- exec_result$stderr
}
cli::cli_abort(
c(
"Unable to execute {.code cargo clean}.",
"x" = paste(err_msg, collapse = "\n")
),
call = caller_env(),
class = "rextendr_error"
)
}
pkgbuild::clean_dll(path = root)
}
173 changes: 98 additions & 75 deletions R/license_note.R
Original file line number Diff line number Diff line change
@@ -1,97 +1,120 @@
#' Generate LICENSE.note file.
#'
#' LICENSE.note generated by this function contains information about Rust crate dependencies.
#' To use this function, the [cargo-license](https://crates.io/crates/cargo-license) command must be installed.
#' @param force Logical indicating whether to regenerate LICENSE.note if LICENSE.note already exists.
#' @inheritParams register_extendr
JosiahParry marked this conversation as resolved.
Show resolved Hide resolved
#' LICENSE.note generated by this function contains information about all
#' recursive dependencies in Rust crate.
#'
#' @param path character scalar, the R package directory
JosiahParry marked this conversation as resolved.
Show resolved Hide resolved
#' @param echo logical scalar, whether to print cargo command and outputs to the
#' console (default is `TRUE`)
#' @param quiet logical scalar, whether to signal successful writing of
#' LICENSE.note (default is `FALSE`)
JosiahParry marked this conversation as resolved.
Show resolved Hide resolved
#' @param overwrite logical scalar, whether to regenerate LICENSE.note if
#' LICENSE.note already exists (default is `TRUE`)
#'
#' @return No return value, called for side effects.
#'
#' @export
write_license_note <- function(path = ".", quiet = FALSE, force = TRUE) {
if (!cargo_command_available(c("license", "--help"))) {
cli::cli_abort(
c(
"The {.code cargo license} command is required to run the {.fun write_license_note} function.",
"*" = "Please install cargo-license ({.url https://crates.io/crates/cargo-license}) first.",
i = "Run {.code cargo install cargo-license} from your terminal."
),
class = "rextendr_error"
)
}
#'
#' @examples
#' \dontrun{
#' write_license_note()
#' }
write_license_note <- function(
path = ".",
echo = TRUE,
quiet = FALSE,
overwrite = TRUE) {
check_string(path, class = "rextendr_error")
check_bool(echo, class = "rextendr_error")
check_bool(quiet, class = "rextendr_error")
check_bool(overwrite, class = "rextendr_error")

Check warning on line 30 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L27-L30

Added lines #L27 - L30 were not covered by tests

outfile <- rprojroot::find_package_root_file(
"LICENSE.note",
path = path
)

Check warning on line 35 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L32-L35

Added lines #L32 - L35 were not covered by tests

metadata <- read_cargo_metadata(
path = path,
dependencies = TRUE
)

Check warning on line 40 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L37-L40

Added lines #L37 - L40 were not covered by tests
JosiahParry marked this conversation as resolved.
Show resolved Hide resolved

manifest_file <- rprojroot::find_package_root_file("src", "rust", "Cargo.toml", path = path)
outfile <- rprojroot::find_package_root_file("LICENSE.note", path = path)
packages <- metadata[["packages"]]

Check warning on line 42 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L42

Added line #L42 was not covered by tests

if (!isTRUE(force) && file.exists(outfile)) {
cli::cli_abort(
c(
"LICENSE.note already exists.",
"If you want to regenerate LICENSE.note, set `force = TRUE` to {.fun write_license_note}."
),
class = "rextendr_error"
)
# exclude current package from LICENSE.note
current_package <- metadata[["resolve"]][["root"]]

Check warning on line 45 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L45

Added line #L45 was not covered by tests
JosiahParry marked this conversation as resolved.
Show resolved Hide resolved

packages <- packages[packages[["id"]] != current_package, ]

Check warning on line 47 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L47

Added line #L47 was not covered by tests

replace_na <- function(data, replace = NA, ...) {
if (vctrs::vec_any_missing(data)) {
missing <- vctrs::vec_detect_missing(data)
data <- vctrs::vec_assign(data, missing, replace,
x_arg = "data",
value_arg = "replace"
)
}
JosiahParry marked this conversation as resolved.
Show resolved Hide resolved
data

Check warning on line 57 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L49-L57

Added lines #L49 - L57 were not covered by tests
}

list_license <- processx::run(
"cargo",
c(
"license",
"--authors",
"--json",
"--avoid-build-deps",
"--avoid-dev-deps",
"--manifest-path", manifest_file
)
)$stdout %>%
jsonlite::parse_json()

package_names <- processx::run(
"cargo",
c(
"metadata",
"--no-deps",
"--format-version", "1",
"--manifest-path", manifest_file
packages[["respository"]] <- replace_na(
packages[["repository"]],
"unknown"
)

Check warning on line 63 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L60-L63

Added lines #L60 - L63 were not covered by tests

packages[["licenses"]] <- replace_na(
packages[["repository"]],
"not provided"
)

Check warning on line 68 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L65-L68

Added lines #L65 - L68 were not covered by tests

prep_authors <- function(authors, package) {
authors <- ifelse(
is.na(authors),
paste0(package, " authors"),
authors

Check warning on line 74 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L70-L74

Added lines #L70 - L74 were not covered by tests
JosiahParry marked this conversation as resolved.
Show resolved Hide resolved
)
)$stdout %>%
jsonlite::parse_json() %>%
purrr::pluck("packages") %>%
purrr::map_chr("name")

.prep_authors <- function(authors, package) {
ifelse(!is.null(authors), authors, paste0(package, " authors")) %>%
stringi::stri_replace_all_regex(r"(\ <.+?>)", "") %>%
stringi::stri_replace_all_regex(r"(\|)", ", ")

authors <- stringi::stri_replace_all_regex(authors, r"(\ <.+?>)", "")

Check warning on line 77 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L77

Added line #L77 was not covered by tests

paste0(authors, collapse = ", ")

Check warning on line 79 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L79

Added line #L79 was not covered by tests
}

packages[["authors"]] <- unlist(Map(
prep_authors,
packages[["authors"]],
packages[["name"]]
))

Check warning on line 86 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L82-L86

Added lines #L82 - L86 were not covered by tests
JosiahParry marked this conversation as resolved.
Show resolved Hide resolved

separator <- "-------------------------------------------------------------"

note_header <- paste0(
"The binary compiled from the source code of this package contains the following Rust crates:\n",
"\n",
"\n",
separator
note_header <- glue::glue(
"
The binary compiled from the source code of this package \\
JosiahParry marked this conversation as resolved.
Show resolved Hide resolved
contains the following Rust crates:

Check warning on line 93 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L90-L93

Added lines #L90 - L93 were not covered by tests


{separator}
"

Check warning on line 97 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L96-L97

Added lines #L96 - L97 were not covered by tests
)

note_body <- list_license %>%
purrr::discard(function(x) x$name %in% package_names) %>%
purrr::map_chr(
function(x) {
paste0(
"\n",
"Name: ", x$name, "\n",
"Repository: ", x$repository, "\n",
"Authors: ", .prep_authors(x$authors, x$name), "\n",
"License: ", x$license, "\n",
"\n",
separator
)
}
)
note_body <- glue::glue_data(
packages,
"

Check warning on line 102 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L100-L102

Added lines #L100 - L102 were not covered by tests

Name: {name}
Repository: {repository}
Authors: {authors}
License: {license}

Check warning on line 107 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L104-L107

Added lines #L104 - L107 were not covered by tests
JosiahParry marked this conversation as resolved.
Show resolved Hide resolved

{separator}
"
)

Check warning on line 111 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L109-L111

Added lines #L109 - L111 were not covered by tests

write_file(
text = c(note_header, note_body),
path = outfile,
search_root_from = path,
quiet = quiet
quiet = quiet,
overwrite = overwrite

Check warning on line 118 in R/license_note.R

View check run for this annotation

Codecov / codecov/patch

R/license_note.R#L117-L118

Added lines #L117 - L118 were not covered by tests
JosiahParry marked this conversation as resolved.
Show resolved Hide resolved
)
}
46 changes: 36 additions & 10 deletions R/read_cargo_metadata.R
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#' Retrieve metadata for packages and workspaces
#'
#' @param path character scalar, the R package directory
#' @param dependencies logical scalar, whether to include all recursive
#' dependencies in stdout (default is FALSE)
#' @param echo logical scalar, should cargo command and outputs be printed to
#' console (default is TRUE)
JosiahParry marked this conversation as resolved.
Show resolved Hide resolved
#'
#' @details
#' For more details, see
Expand All @@ -25,22 +29,44 @@
#' read_cargo_metadata()
#' }
#'
read_cargo_metadata <- function(path = ".") {
read_cargo_metadata <- function(
path = ".",
dependencies = FALSE,
echo = TRUE) {
check_string(path, class = "rextendr_error")
check_bool(dependencies, class = "rextendr_error")
check_bool(echo, class = "rextendr_error")

root <- rprojroot::find_package_root_file(path = path)
rust_folder <- rprojroot::find_package_root_file(
"src", "rust",
path = path
)

rust_folder <- normalizePath(
file.path(root, "src", "rust"),
winslash = "/",
mustWork = FALSE
args <- c(
"metadata",
"--format-version=1",
if (isFALSE(dependencies)) {
"--no-deps"
},
if (tty_has_colors()) {
"--color=always"

Check warning on line 52 in R/read_cargo_metadata.R

View check run for this annotation

Codecov / codecov/patch

R/read_cargo_metadata.R#L52

Added line #L52 was not covered by tests
} else {
"--color=never"
}
)

out <- processx::run(
JosiahParry marked this conversation as resolved.
Show resolved Hide resolved
"cargo",
args = c("metadata", "--format-version=1", "--no-deps"),
wd = rust_folder
command = "cargo",
args = args,
error_on_status = TRUE,
wd = rust_folder,
echo_cmd = echo,
echo = echo,
env = get_cargo_envvars()
)

jsonlite::fromJSON(out[["stdout"]])
jsonlite::parse_json(
out[["stdout"]],
JosiahParry marked this conversation as resolved.
Show resolved Hide resolved
simplifyDataFrame = TRUE
)
}
Loading
Loading