| # File src/library/utils/R/changedFiles.R |
| # Part of the R package, https://www.R-project.org |
| # |
| # Copyright (C) 2013 The R Core Team |
| # |
| # This program is free software; you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation; either version 2 of the License, or |
| # (at your option) any later version. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # A copy of the GNU General Public License is available at |
| # https://www.R-project.org/Licenses/ |
| |
| fileSnapshot <- function(path = ".", file.info = TRUE, timestamp = NULL, |
| md5sum = FALSE, digest = NULL, |
| full.names = length(path) > 1, ...) { |
| |
| if (length(path) > 1 && !full.names) |
| stop("'full.names' must be TRUE for multiple paths.") |
| |
| if (length(timestamp) == 1) |
| file.create(timestamp) |
| |
| path <- normalizePath(path) |
| args <- list(...) |
| |
| fullnames <- names <- character(0) |
| for (i in seq_along(path)) { |
| newnames <- do.call(list.files, c(path = path[i], full.names = full.names, args)) |
| names <- c(names, newnames) |
| if (full.names) fullnames <- names |
| else fullnames <- c(fullnames, file.path(path[i], newnames)) |
| } |
| |
| if (file.info) { |
| info <- file.info(fullnames) |
| if (!full.names) |
| rownames(info) <- names |
| } else |
| info <- data.frame(row.names = names) |
| |
| if (md5sum) |
| info <- data.frame(info, md5sum = suppressWarnings(tools::md5sum(fullnames)), |
| stringsAsFactors = FALSE) |
| |
| if (!is.null(digest)) |
| info <- data.frame(info, digest = digest(fullnames), stringsAsFactors = FALSE) |
| |
| structure(list(info = info, path = path, timestamp = timestamp, |
| file.info = file.info, md5sum = md5sum, digest = digest, |
| full.names = full.names, args = args), class = "fileSnapshot") |
| } |
| |
| changedFiles <- function(before, after, path = before$path, timestamp = before$timestamp, |
| check.file.info = c("size", "isdir", "mode", "mtime"), |
| md5sum = before$md5sum, digest = before$digest, |
| full.names = before$full.names, ...) { |
| |
| stopifnot(inherits(before, "fileSnapshot")) |
| |
| if (missing(after)) { |
| get.file.info <- length(check.file.info) > 0 && before$file.info |
| |
| args <- before$args |
| newargs <- list(...) |
| args[names(newargs)] <- newargs |
| |
| after <- do.call(fileSnapshot, c(list(path = path, timestamp = NULL, |
| file.info = get.file.info, md5sum = md5sum, |
| digest = digest, full.names = full.names), args)) |
| } |
| stopifnot(inherits(after, "fileSnapshot")) |
| |
| preinfo <- before$info |
| postinfo <- after$info |
| prenames <- rownames(preinfo) |
| postnames <- rownames(postinfo) |
| |
| added <- setdiff(postnames, prenames) |
| deleted <- setdiff(prenames, postnames) |
| common <- intersect(prenames, postnames) |
| |
| if (!before$file.info || !after$file.info) |
| check.file.info <- NULL |
| |
| if (length(check.file.info)) { |
| pre <- preinfo[common, check.file.info, drop = FALSE] |
| post <- postinfo[common, check.file.info, drop = FALSE] |
| changes <- pre != post |
| } |
| else changes <- matrix(logical(0), nrow = length(common), ncol = 0, |
| dimnames = list(common, character(0))) |
| |
| if (length(timestamp)) |
| if (file.exists(timestamp)) { |
| fullnames <- if (after$full.names) common else file.path(after$path, common) |
| changes <- cbind(changes, Newer = file_test("-nt", fullnames, timestamp)) |
| } else |
| warning("Timestamp file no longer exists.") |
| |
| if (md5sum) { |
| pre <- preinfo[common, "md5sum"] |
| post <- postinfo[common, "md5sum"] |
| changes <- cbind(changes, md5sum = pre != post) |
| } |
| |
| if (!is.null(digest)) { |
| pre <- preinfo[common, "digest"] |
| post <- postinfo[common, "digest"] |
| changes <- cbind(changes, digest = pre != post) |
| } |
| changed <- rownames(changes)[rowSums(changes, na.rm = TRUE) > 0] |
| structure(list(added = added, deleted = deleted, changed = changed, |
| unchanged = setdiff(common, changed), changes = changes), |
| class = "changedFiles") |
| } |
| |
| print.fileSnapshot <- function(x, verbose = FALSE, ...) { |
| cat("File snapshot:\n path = ", x$path, |
| "\n timestamp = ", x$timestamp, |
| "\n file.info = ", x$file.info, |
| "\n md5sum = ", x$md5sum, |
| "\n digest = ", deparse(x$digest, control = NULL), |
| "\n full.names = ", x$full.names, |
| "\n args = ", deparse(x$args, control = NULL), |
| "\n ", nrow(x$info), " files recorded.\n", sep="") |
| if (verbose) { |
| if (ncol(x$info)) print(x$info) |
| else cat("Files:", rownames(x$info), sep="\n ") |
| } |
| invisible(x) |
| } |
| |
| print.changedFiles <- function(x, verbose = FALSE, ...) { |
| if (length(x$added)) |
| cat("Files added:\n", paste0(" ", x$added, collapse="\n"), "\n", sep="") |
| if (length(x$deleted)) |
| cat("Files deleted:\n", paste0(" ", x$deleted, collapse="\n"), "\n", sep="") |
| changes <- x$changes |
| if (!verbose) { |
| changes <- changes[rowSums(changes, na.rm = TRUE) > 0, , drop=FALSE] |
| changes <- changes[, colSums(changes, na.rm = TRUE) > 0, drop=FALSE] |
| } |
| if (verbose || nrow(changes)) { |
| cat("File changes:\n") |
| print(changes) |
| } |
| invisible(x) |
| } |