R/extract_and_render.R

Defines functions extract_and_render

Documented in extract_and_render

#' Extract notebooks and render as HTML
#'
#' Given a `.tar.gz` file, this function extracts all of the notebooks
#' associated with the `quiz_name`, organizes them, and renders them as HTML. At
#' the `output_dir`, two directories are created: `source` and `html`.
#' The original `.ipynb` notebooks are renamed `{username}_{quiz_name}.ipynb`
#' and put in the `source` directory, then they are rendered as `html` and the
#' rendered files are put in the `html` directory.
#'
#' @param archive The archive to extract the files from. This should be a
#'   gzipped tar archive. This is the same type of file created by the
#'   \code{\link{get_terminal_command}} function.
#' @param course_name The name of the course to extract the notebooks from.
#' @param quiz_name The name of the quiz to extract notebooks for.
#' @param output_dir The directory the organized notebooks and HTML
#'   files should be output to. It is created if it does not exist.
#' @param exclude A character vector of usernames to exclude from processing.
#' @param invert_exclusions Invert the pattern matching triggered by `exclude`,
#'   essentially turning "exclude" into "keep only".
#'
#' @return The paths to the extracted notebooks (invisibly). The paths are
#'   relative to `output_dir`.
#' @export
extract_and_render <- function(
  archive,
  course_name,
  quiz_name,
  output_dir,
  exclude = NULL,
  invert_exclusions = FALSE
) {
  input_name <- stringr::str_split_fixed(fs::path_file(archive), '[.]', 2)[, 1]
  output_structure <- fs::path(output_dir, input_name, c('.', 'source', 'html'))

  # create the output directory
  fs::dir_create(output_structure[[1]])
  source_dir <- fs::dir_create(output_structure[[2]])
  render_dir <- fs::dir_create(output_structure[[3]])

  # extract the files
  tar_file_glob <- glue::glue('*/{quiz_name}.ipynb')
  file_names <- fs::path_filter(utils::untar(archive, list = TRUE), tar_file_glob)
  if (!purrr::is_empty(exclude)) {
    file_names <- fs::path_filter(
      file_names,
      regex = paste0(glue::glue('{exclude}/.*'), collapse = '|'),
      invert = !invert_exclusions
    )
  }
  utils::untar(archive, files = file_names, exdir = source_dir)

  # unnest the files
  file_paths <- fs::path(source_dir, file_names)
  path_parts <- stringr::str_split_fixed(file_names, '/', 5)
  new_file_names <- paste0(path_parts[, 3], '_', path_parts[, 5])
  new_file_paths <- fs::path(source_dir, new_file_names)
  fs::file_move(file_paths, new_file_paths)
  fs::dir_delete(fs::path(source_dir, course_name))

  # render the files as HTML
  command <- stringr::str_c('jupyter nbconvert ', stringr::str_c(new_file_paths, collapse = ' '))
  system(command, show.output.on.console = FALSE)
  html_files <- fs::dir_ls(source_dir, regexp = '[.]html$')
  fs::file_move(html_files, fs::path(render_dir, fs::path_file(html_files)))

  invisible(new_file_paths)
}
adamblake/nbsimplegrader_companion documentation built on April 19, 2020, 6:05 p.m.