diff --git a/DESCRIPTION b/DESCRIPTION index 760a4dab..c6880bc0 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -15,6 +15,7 @@ Imports: callr, checkmate, cli, + fs, gh, glue, jsonlite, diff --git a/NAMESPACE b/NAMESPACE index c19a4fb5..d33cf3e3 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -10,14 +10,18 @@ export(init_tic) export(renv_downgrade) export(renv_install_local) export(renv_switch_r_version) +export(use_cmakelists) +export(use_gitpod) importFrom(checkmate,assert_character) importFrom(cli,cli_alert) +importFrom(fs,dir_create) importFrom(gh,gh) importFrom(jsonlite,read_json) importFrom(lifecycle,deprecated) importFrom(renv,install) importFrom(rstudioapi,restartSession) importFrom(usethis,use_package) +importFrom(usethis,use_template) importFrom(usethis,use_tidy_description) importFrom(utils,available.packages) importFrom(utils,download.file) diff --git a/R/use_cmakelists.R b/R/use_cmakelists.R new file mode 100644 index 00000000..bae7854d --- /dev/null +++ b/R/use_cmakelists.R @@ -0,0 +1,61 @@ +#' Initialize CMakeLists configuration +#' +#' @description +#' Initializes a `CMakeLists.txt` at the current working directory and at the `src/` +#' folder with the necessary configuration information +#' +#' @param project `[character]`\cr +#' The name of the R project +#' +#' @examples +#' \dontrun{ +#' use_cmakelists("Your_Project_Name") +#' } +#' @importFrom usethis use_template +#' @importFrom fs dir_create +#' @export +use_cmakelists <- function(project = NULL) { + generator <- "Generated by cynkrathis::use_cmakelists(), do not edit by hand" + deparsed_call <- prepend(capture_call(sys.call()), "# ") + + if (is.null(project)) { + project <- desc::desc_get_field("Package") + } + + new_cmakelist <- usethis::use_template( + "CMakeLists.txt", + "CMakeLists.txt", + package = "cynkrathis", + data = list( + generator = generator, + call = deparsed_call, + project = project + ), + ignore = TRUE + ) + + fs::dir_create("src") + + ext_files <- list.files(path = "src", pattern = "\\.(c|h|cpp)$") + ext_files <- withr::with_collate("C", prepend(sort(ext_files), " ")) + + deps <- desc::desc_get_deps() + linking_to_deps <- deps$package[deps$type == "LinkingTo"] + linking_to_deps <- withr::with_collate("C", paste0(sort(linking_to_deps), collapse = " ")) + + new_cmakelist_src <- usethis::use_template( + "CMakeLists-src.txt", + "src/CMakeLists.txt", + package = "cynkrathis", + data = list( + generator = generator, + call = deparsed_call, + project = project, + ext_files = ext_files, + linking_to_deps = linking_to_deps + ), + ignore = FALSE + ) + + invisible(new_cmakelist || new_cmakelist_src) +} diff --git a/R/use_gitpod.R b/R/use_gitpod.R new file mode 100644 index 00000000..321e5542 --- /dev/null +++ b/R/use_gitpod.R @@ -0,0 +1,48 @@ +#' Initialize gitpod configuration +#' +#' @description +#' Initializes `.gitpod.Dockerfile` and `.gitpod.yml` at the working directory +#' with the necessary gitpod configuration information +#' +#' @param apt_packages Additional `apt` packages to install in the Docker image. +#' @param user_code User code to configure in `.gitpod.yml` +#' +#' @examples +#' \dontrun{ +#' use_gitpod() +#' } +#' @importFrom usethis use_template +#' @export +use_gitpod <- function(apt_packages = NULL, user_code = NULL) { + generator <- "Generated by cynkrathis::use_gitpod(), do not edit by hand" + deparsed_apt_packages <- paste(apt_packages, collapse = " ") + deparsed_user_code <- prepend(user_code, " ") + deparsed_call <- prepend(capture_call(sys.call()), "# ") + + new_gitpod_yml <- usethis::use_template( + "gitpod.yml", + ".gitpod.yml", + data = list( + generator = generator, + user_code = deparsed_user_code, + call = deparsed_call + ), + package = "cynkrathis", + ignore = TRUE + ) + + invisible(new_gitpod_yml) +} + +prepend <- function(x, prefix) { + if (is.null(x)) { + return("") + } + x_vec <- unlist(strsplit(x, "\n")) + x_prefix <- gsub("^ *", prefix, x_vec) + paste0(x_prefix, collapse = "\n") +} + +capture_call <- function(call) { + capture.output(print(constructive::construct(call))) +} diff --git a/inst/templates/CMakeLists-src.txt b/inst/templates/CMakeLists-src.txt new file mode 100644 index 00000000..7cc97cba --- /dev/null +++ b/inst/templates/CMakeLists-src.txt @@ -0,0 +1,31 @@ +# {{{generator}}} +# +# Call: +{{{call}}} + +add_library({{{project}}} +{{{ext_files}}} +) + +set(R_DEPENDENCIES {{{linking_to_deps}}}) + +execute_process(COMMAND bash "-c" "Rscript -e 'cat(R.home(\"include\"))'" OUTPUT_VARIABLE R_INCLUDE) +execute_process(COMMAND bash "-c" "Rscript -e 'cat(.libPaths()[[1]])'" OUTPUT_VARIABLE R_LIBDIR) + +foreach(PKG_NAME IN LISTS R_DEPENDENCIES) + list(APPEND R_PKG_INCLUDE_LIST "${R_LIBDIR}/${PKG_NAME}/include") +endforeach() +message("${R_PKG_INCLUDE_LIST}") + +target_include_directories({{{project}}} PUBLIC + ${R_PKG_INCLUDE_LIST} + ${R_INCLUDE} + # Included by default + "." + "vendor" +) + +get_target_property(include_dirs {{{project}}} INTERFACE_INCLUDE_DIRECTORIES) +message("${include_dirs}") + +include(./custom.cmake OPTIONAL) diff --git a/inst/templates/CMakeLists.txt b/inst/templates/CMakeLists.txt new file mode 100644 index 00000000..058ce015 --- /dev/null +++ b/inst/templates/CMakeLists.txt @@ -0,0 +1,11 @@ +# {{{generator}}} +# +# Call: +{{{call}}} + +cmake_minimum_required(VERSION 3.14) +project({{{project}}} VERSION 0.1.0) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +add_subdirectory(src) diff --git a/inst/templates/gitpod.yml b/inst/templates/gitpod.yml new file mode 100644 index 00000000..65fff4a3 --- /dev/null +++ b/inst/templates/gitpod.yml @@ -0,0 +1,65 @@ +# {{{generator}}} +# +# Call: +{{{call}}} + +tasks: + - name: dependencies + init: | + # Set up rig + curl -Ls https://github.com/r-lib/rig/releases/download/latest/rig-linux-latest.tar.gz | sudo tar xz -C /usr/local + + # Set up R + rig install + rig system add-pak --pak-version devel + rig system make-links + rig system setup-user-lib + + # Deps + sudo apt install -y ccache cmake + + # Scriptlets, with custom Git config + mv ~/.gitconfig ~/.gitconfig.gitpod + curl -s https://raw.githubusercontent.com/krlmlr/scriptlets/master/bootstrap | sh + + ## .editorconfig + ln -s ~/.editorconfig .. + + ## Set up ccache + ln -s /usr/lib/ccache/* ~/bin/ + + ## Work around glitch with non-systemd systems + ln -s $(which true) ~/bin/timedatectl + + ## Define PATH + # FIXME: Why is this necessary? This doesn't work in Radian. + echo 'export PATH='${HOME}'/bin:${PATH}' >> ~/.bashrc + + # Set up Makevars + mkdir -p ~/.R + echo -e "MAKEFLAGS = -j8\nCXXFLAGS = -O0 -g" > ~/.R/Makevars + + # Install R packages + echo 'options(repos = "https://packagemanager.rstudio.com/all/__linux__/'$(cat /etc/lsb-release | sed -n '/DISTRIB_CODENAME=/ {s///;p}')'/latest")' >> ~/.Rprofile + + ## Install devtools and R dependencies + R -q -e 'pak::pak(c("devtools", "languageserver", "styler", "krlmlr/lazytest"); pak::pak()' + + # Install radian + sudo pip install radian + + # Run custom code + if [ -x tools/gitpod.sh ]; then tools/gitpod.sh; fi + +vscode: + extensions: + - ms-vscode.cpptools + # needs reload of VS Code to be operational + - go2sh.cmake-integration-vscode + # buggy -- doesn't reliably interpret include files? + # observed behavior: repeated saving of src/CMakeLists.txt + # changes detaction of include files -- sometimes it works, sometimes it doesn't, + # with no detectable pattern + # - ms-vscode.cmake-tools + - EditorConfig.EditorConfig + - REditorSupport.r diff --git a/man/use_cmakelists.Rd b/man/use_cmakelists.Rd new file mode 100644 index 00000000..718a5faa --- /dev/null +++ b/man/use_cmakelists.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/use_cmakelists.R +\name{use_cmakelists} +\alias{use_cmakelists} +\title{Initialize CMakeLists configuration} +\usage{ +use_cmakelists(project = NULL) +} +\arguments{ +\item{project}{\verb{[character]}\cr +The name of the R project} +} +\description{ +Initializes a \code{CMakeLists.txt} at the current working directory and at the \verb{src/} +folder with the necessary configuration information +} +\examples{ +\dontrun{ +use_cmakelists("Your_Project_Name") +} +} diff --git a/man/use_gitpod.Rd b/man/use_gitpod.Rd new file mode 100644 index 00000000..3ccbd2c2 --- /dev/null +++ b/man/use_gitpod.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/use_gitpod.R +\name{use_gitpod} +\alias{use_gitpod} +\title{Initialize gitpod configuration} +\usage{ +use_gitpod(apt_packages = NULL, user_code = NULL) +} +\arguments{ +\item{apt_packages}{Additional \code{apt} packages to install in the Docker image.} + +\item{user_code}{User code to configure in \code{.gitpod.yml}} +} +\description{ +Initializes \code{.gitpod.Dockerfile} and \code{.gitpod.yml} at the working directory +with the necessary gitpod configuration information +} +\examples{ +\dontrun{ +use_gitpod() +} +} diff --git a/pkgdown/_pkgdown.yml b/pkgdown/_pkgdown.yml index 8df58a8a..e05956e9 100644 --- a/pkgdown/_pkgdown.yml +++ b/pkgdown/_pkgdown.yml @@ -31,3 +31,5 @@ reference: - init_tic - init_gitignore - init_lintr + - use_gitpod + - use_cmakelists