diff --git a/.Rbuildignore b/.Rbuildignore index 48016d4..a9e16b4 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -5,3 +5,4 @@ ^README\.*html$ ^NOTES\.*Rmd$ ^NOTES\.*html$ +^tools$ \ No newline at end of file diff --git a/DESCRIPTION b/DESCRIPTION index 3a6bac1..60631dc 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -2,7 +2,7 @@ Package: wand Type: Package Title: Retrieve 'Magic' Attributes from Files and Directories Version: 0.2.0 -Date: 2016-08-13 +Date: 2016-08-14 Author: Bob Rudis (@hrbrmstr), Christos Zoulas [libmagic] Maintainer: Bob Rudis Description: The 'libmagic' library provides functions to determine @@ -10,13 +10,12 @@ Description: The 'libmagic' library provides functions to determine attributes. URL: http://github.com/hrbrmstr/wand BugReports: https://github.com/hrbrmstr/wand/issues -SystemRequirements: libmagic (>= 5.14) +SystemRequirements: libmagic (>= 5.14) for Unix/Linux/macOS; Rtools 3.3+ for Windows License: AGPL Suggests: - testthat, - magrittr + testthat Depends: - R (>= 3.0.0) + R (>= 3.2.0) Imports: purrr, Rcpp, diff --git a/NAMESPACE b/NAMESPACE index b17e4ed..9b9542c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -10,6 +10,7 @@ import(tidyr) importFrom(Rcpp,sourceCpp) importFrom(dplyr,left_join) importFrom(dplyr,mutate) +importFrom(dplyr,mutate_all) importFrom(rappdirs,user_cache_dir) importFrom(utils,unzip) useDynLib(wand) diff --git a/R/wand-package.R b/R/wand-package.R index 81644a8..fba0632 100644 --- a/R/wand-package.R +++ b/R/wand-package.R @@ -11,6 +11,6 @@ #' @useDynLib wand #' @importFrom Rcpp sourceCpp #' @importFrom utils unzip -#' @importFrom dplyr mutate left_join +#' @importFrom dplyr mutate left_join mutate_all #' @import stats NULL diff --git a/R/wand.r b/R/wand.r index 3e53579..ff1e6de 100644 --- a/R/wand.r +++ b/R/wand.r @@ -3,7 +3,8 @@ #' @param path character vector of files to use magic on #' @param magic_db either "\code{system}" (the default) to use the system #' \code{magic} database or an atomic character vector with a -#' colon-separated list of full paths to custom \code{magic} database(s). +#' colon-separated list of full paths to custom \code{magic} database(s). This parameter +#' is (for the moment) ignored on Windows. #' @return a \code{tibble} / \code{data.frame} of file magic attributes. #' Specifically, mime type, encoding, possible file extensions and #' type description are returned as colums in the data frame along @@ -14,7 +15,6 @@ #' for information on how to create your own \code{magic} database #' @export #' @examples -#' library(magrittr) #' library(dplyr) #' #' system.file("img", package="filemagic") %>% @@ -25,24 +25,41 @@ incant <- function(path, magic_db="system") { if (get_os() == "win") { - file_exe <- system.file("exec/file.exe", package="wand") + found_file <- FALSE + + file_exe <- Sys.which("file.exe") + found_file <- file_exe != "" + + if (found_file) { + file_version <- suppressWarnings(system2(file_exe, "--version", stdout=TRUE, stderr=TRUE)) + found_file <- any(grepl("magic file", file_version)) + } + + if (!found_file) { + stop(paste0("'file.exe' not found. Please install 'Rtools' and restart R. ", + "See 'https://github.com/stan-dev/rstan/wiki/Install-Rtools-for-Windows' ", + "for more information on how to install 'Rtools'", collapse=""), + call.=FALSE) + } magic_db <- normalizePath(magic_wand_file()) tf <- tempfile() writeLines(path, tf) - system2(file_exe, + suppressMessages( + suppressWarnings( + system2(file_exe, c("--mime-type", "--mime-encoding", "--no-buffer", "--preserve-date", - '--separator "||"', sprintf('--magic-file "%s"', magic_db), + '--separator "||"', sprintf('--files-from "%s"', tf)), - stdout=TRUE) -> output_1 + stdout=TRUE))) -> output_1 - system2(file_exe, + suppressMessages( + suppressWarnings(system2(file_exe, c("--no-buffer", "--preserve-date", '--separator "||"', - sprintf('--magic-file "%s"', magic_db), sprintf('--files-from "%s"', tf)), - stdout=TRUE) -> output_2 + stdout=TRUE))) -> output_2 unlink(tf) @@ -56,13 +73,15 @@ incant <- function(path, magic_db="system") { as_data_frame() %>% setNames(c("file", "description")) -> df2 - left_join(df1, df2, by="file") + left_join(df1, df2, by="file") %>% + mutate_all(stri_trim_both) } else { incant_(path, magic_db) } } +#' ripped from rappdirs (ty Hadley!) get_os <- function () { if (.Platform$OS.type == "windows") { "win" diff --git a/R/zzz.r b/R/zzz.r index 7fbbb2b..86c15f9 100644 --- a/R/zzz.r +++ b/R/zzz.r @@ -10,9 +10,12 @@ #' #' @param refresh ensure the lastest copy of the pacakge "magic" #' database is used. +#' @note 'magic' files are highly coupled with the version of the \code{file} +#' utility they were built with. This function is provided solely for the +#' off chance that a macOS or Linux/UNIX system's \code{libmagic} library +#' was not configured properly and cannot find the system 'magic' file. #' @export #' @examples -#' library(magrittr) #' library(dplyr) #' #' system.file("img", package="filemagic") %>% @@ -27,7 +30,6 @@ magic_wand_file <- function(refresh=FALSE) { if (!dir.exists(cache)) return(NULL) if (lib_version() >= 528) vers <- "new" else vers <- "old" - if (get_os() == "win") vers <- "win" if (refresh | (!file.exists(file.path(rappdirs::user_cache_dir("wandr"), "magic.mgc")))) { unzip(system.file("db", vers, "magic.mgc.zip", package="wand"), diff --git a/README.Rmd b/README.Rmd index 4044888..5818bb6 100644 --- a/README.Rmd +++ b/README.Rmd @@ -13,7 +13,7 @@ The `libmagic` library must be installed on *nix/macOS and available to use this While the package was developed using the 5.28 version of `libmagic` it has been configured to work with older versions. Note that some fields in the resultant data frame might not be available with older library versions. When using the function `magic_wand_file()` it checks for which version of `libmagic` is installed on your system and provides a suitable `magic.mgc` file for it. -The package also works on Windows but it's a bit of a hack because, well, _Windows_. Seriously, folks, use a real operating system. The Windows version makes two `system2()` calls, so it's sub-optimal at best. Help to get it working in C would be greatly appreciated. +The package also works on Windows but it's a bit of a hack because, well, _Windows_. The Windows version makes two `system2()` calls and relies on Rtools being installed and `file.exe` being available on the Windows `PATH`, so it's sub-optimal at best. Help to get it working in C would be greatly appreciated. The following functions are implemented: @@ -42,6 +42,8 @@ system.file("img", package="wand") %>% incant() %>% glimpse() +# Use a non-system magic-file + system.file("img", package="wand") %>% list.files(full.names=TRUE) %>% incant(magic_wand_file()) %>% diff --git a/README.md b/README.md index 002f9b6..dfd5033 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The `libmagic` library must be installed on \*nix/macOS and available to use thi While the package was developed using the 5.28 version of `libmagic` it has been configured to work with older versions. Note that some fields in the resultant data frame might not be available with older library versions. When using the function `magic_wand_file()` it checks for which version of `libmagic` is installed on your system and provides a suitable `magic.mgc` file for it. -The package also works on Windows but it's a bit of a hack because, well, *Windows*. Seriously, folks, use a real operating system. The Windows version makes two `system2()` calls, so it's sub-optimal at best. Help to get it working in C would be greatly appreciated. +The package also works on Windows but it's a bit of a hack because, well, *Windows*. The Windows version makes two `system2()` calls and relies on Rtools being installed and `file.exe` being available on the Windows `PATH`, so it's sub-optimal at best. Help to get it working in C would be greatly appreciated. The following functions are implemented: @@ -79,7 +79,7 @@ library(testthat) date() ``` - ## [1] "Sun Aug 14 18:36:44 2016" + ## [1] "Mon Aug 15 08:17:44 2016" ``` r test_dir("tests/") diff --git a/inst/db/win/magic.mgc.zip b/inst/db/win/magic.mgc.zip deleted file mode 100644 index fac0865..0000000 Binary files a/inst/db/win/magic.mgc.zip and /dev/null differ diff --git a/inst/exec/file.exe b/inst/exec/file.exe deleted file mode 100755 index 44eab60..0000000 Binary files a/inst/exec/file.exe and /dev/null differ diff --git a/man/get_os.Rd b/man/get_os.Rd new file mode 100644 index 0000000..bec2d3e --- /dev/null +++ b/man/get_os.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wand.r +\name{get_os} +\alias{get_os} +\title{ripped from rappdirs (ty Hadley!)} +\usage{ +get_os() +} +\description{ +ripped from rappdirs (ty Hadley!) +} + diff --git a/man/incant.Rd b/man/incant.Rd index 2063a0a..fd72c65 100644 --- a/man/incant.Rd +++ b/man/incant.Rd @@ -11,7 +11,8 @@ incant(path, magic_db = "system") \item{magic_db}{either "\code{system}" (the default) to use the system \code{magic} database or an atomic character vector with a -colon-separated list of full paths to custom \code{magic} database(s).} +colon-separated list of full paths to custom \code{magic} database(s). This parameter +is (for the moment) ignored on Windows.} } \value{ a \code{tibble} / \code{data.frame} of file magic attributes. @@ -27,7 +28,6 @@ Various fields might not be available depending on the version of \code{libmagic} you have installed. } \examples{ -library(magrittr) library(dplyr) system.file("img", package="filemagic") \%>\% diff --git a/man/magic_wand_file.Rd b/man/magic_wand_file.Rd index 2e19b27..e7b9490 100644 --- a/man/magic_wand_file.Rd +++ b/man/magic_wand_file.Rd @@ -19,8 +19,13 @@ return the full path to the magic file. Subsequent calls will not have to perform the decompression unless \code{force} is \code{TRUE} or the cache directory has been cleared. } +\note{ +'magic' files are highly coupled with the version of the \code{file} + utility they were built with. This function is provided solely for the + off chance that a macOS or Linux/UNIX system's \code{libmagic} library + was not configured properly and cannot find the system 'magic' file. +} \examples{ -library(magrittr) library(dplyr) system.file("img", package="filemagic") \%>\% diff --git a/src/Makevars b/src/Makevars index 9e2918a..dc62823 100644 --- a/src/Makevars +++ b/src/Makevars @@ -1,8 +1,2 @@ PKG_LIBS = -lmagic -all: clean - -clean: - rm -f $(OBJECTS) wand.dll - -.PHONY: all clean \ No newline at end of file diff --git a/src/Makevars.win b/src/Makevars.win index 27a2011..170ffab 100755 --- a/src/Makevars.win +++ b/src/Makevars.win @@ -1,9 +1,6 @@ -all: winlibs +all: clean clean: rm -f $(OBJECTS) wand.dll -winlibs: - "${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" "../tools/getfile.R" - -.PHONY: all winlibs clean \ No newline at end of file +.PHONY: all clean \ No newline at end of file diff --git a/src/wand.cpp b/src/wand.cpp index 13e7483..5514909 100644 --- a/src/wand.cpp +++ b/src/wand.cpp @@ -42,6 +42,12 @@ DataFrame incant_(CharacterVector path, std::string magic_db="system") { mdb = mdbcpp.c_str(); } + // This is "ugh" due to the fact that various versions of the libmagic + // library can't handle loading multiple "cookies" at the same time. + // So, we end up doing way too much extra work to get the individual + // bits of info. I may just switch this over to a single call (all the + // availabel flags) and do string parsing before pushing to CRAN. + for (unsigned int i=0; i