yihui / servr

A simple HTTP server in R
https://cran.rstudio.com/package=servr
278 stars 35 forks source link

Use Perl-like regex for file matching #51

Closed ARawles closed 3 years ago

ARawles commented 4 years ago

I'm attempting to use a Docker container hosting a servr server serving a CRAN-like repository that monitors for changes and them automatically updates the PACKAGE files once a package is uploaded.

But unfortunately, the list.files() pattern argument uses the extended regex engine rather than Perl, meaning that you can't use negative look-around. The upshot being that servr monitors the repo, detects a change, runs the handler function which updates the PACKAGE files, but because I can't use the pattern parameter to exclude monitoring of files that match the "PACKAGE" name, servr detects another directory change and so runs the handler function again, which updates the PACKAGE files and so on...

If the pattern parameter for the httw function accepted Perl-like regex however, then I would be able to exclude monitoring of PACKAGE* files and we wouldn't see this loop. Enabling this would only require a single change to the watch_dir function:

...
    info = file.info(list.files(
      dir, pattern, all.files = all_files, full.names = TRUE, recursive = TRUE,
      no.. = TRUE
    ))[, 'mtime', drop = FALSE]
...

would need to become

...
    files <- list.files(
      dir,
      all.files = all_files, full.names = TRUE, recursive = TRUE,
      no.. = TRUE
    )
    if (!is.null(pattern)){
      files <- grep(pattern,
                    files,
                    perl = TRUE,
                    value = TRUE
      )
    }
    info = file.info(files)[, 'mtime', drop = FALSE]
...

Happy to raise a PR if you're happy.

ARawles commented 4 years ago

Looking deeper, there appears to be another function that uses list.files() pattern matching that would also need to be updated:

# watch files with pattern, and rebuild them if necessary
build_watcher = function(pattern, build, dir = getwd()) {
  source_info = function() {
    file.info(list.files(dir, pattern, recursive = TRUE))[, 'mtime', drop = FALSE]
  }
...
}

I've added the necessary changes to this function to the PR.