From 3ed9508453c2be38c98a0b8b90a4c35e9f187307 Mon Sep 17 00:00:00 2001 From: boB Rudis Date: Wed, 21 Mar 2018 09:29:18 -0400 Subject: [PATCH] iOS and more utility functions --- NAMESPACE | 5 +- NEWS.md | 4 +- R/RcppExports.R | 6 +- R/ios.R | 62 +++++++++++++++++++++ R/lighttpd.R | 2 +- R/utils.R | 34 +++++++++++ R/vershist-package.R | 1 + README.Rmd | 25 ++++++++- README.md | 50 ++++++++++++++++- ...pple_ios_c87a0ba8187fd58c6318fd9ff44ca2a6.RData | Bin 0 -> 3034 bytes .../apple_ios_c87a0ba8187fd58c6318fd9ff44ca2a6.rdb | 0 .../apple_ios_c87a0ba8187fd58c6318fd9ff44ca2a6.rdx | Bin 0 -> 113 bytes man/apple_ios_version_history.Rd | 19 +++++++ man/complete_semver.Rd | 23 ++++++++ man/is_valid.Rd | 14 ----- man/is_valid_semver.Rd | 14 +++++ man/lighttpd_version_history.Rd | 2 +- src/RcppExports.cpp | 10 ++-- src/vershist-main.cpp | 4 +- 19 files changed, 244 insertions(+), 31 deletions(-) create mode 100644 R/ios.R create mode 100644 R/utils.R create mode 100644 README_cache/gfm/apple_ios_c87a0ba8187fd58c6318fd9ff44ca2a6.RData create mode 100644 README_cache/gfm/apple_ios_c87a0ba8187fd58c6318fd9ff44ca2a6.rdb create mode 100644 README_cache/gfm/apple_ios_c87a0ba8187fd58c6318fd9ff44ca2a6.rdx create mode 100644 man/apple_ios_version_history.Rd create mode 100644 man/complete_semver.Rd delete mode 100644 man/is_valid.Rd create mode 100644 man/is_valid_semver.Rd diff --git a/NAMESPACE b/NAMESPACE index 1fed441..7a5d4bd 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,8 +1,10 @@ # Generated by roxygen2: do not edit by hand export(apache_httpd_version_history) +export(apple_ios_version_history) +export(complete_semver) export(google_chrome_version_history) -export(is_valid) +export(is_valid_semver) export(lighttpd_version_history) export(memcached_version_history) export(mongodb_version_history) @@ -50,6 +52,7 @@ importFrom(rvest,xml_nodes) importFrom(stringi,stri_count_fixed) importFrom(stringi,stri_detect_fixed) importFrom(stringi,stri_detect_regex) +importFrom(stringi,stri_extract_all_regex) importFrom(stringi,stri_extract_first_regex) importFrom(stringi,stri_match_first_regex) importFrom(stringi,stri_replace_all_fixed) diff --git a/NEWS.md b/NEWS.md index f203403..6ed7383 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ 0.1.0 * Initial release -* Support for Apache httpd, Google Chrome lighttpd, memcached, mongodb, nginx, mysql, - openresty, openssh, sendmail and sqlite \ No newline at end of file +* Support for Apache httpd, Apple iOS, Google Chrome lighttpd, memcached, mongodb, nginx, + mysql, openresty, openssh, sendmail and sqlite \ No newline at end of file diff --git a/R/RcppExports.R b/R/RcppExports.R index 6a6ec6c..b943091 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -1,11 +1,11 @@ # Generated by using Rcpp::compileAttributes() -> do not edit by hand # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 -#' Test if semantic version strings are valid +#' Test if semantic version strings are valid tri-string #' #' @param v character verctor of version strings #' @export -is_valid <- function(v) { - .Call('_vershist_is_valid', PACKAGE = 'vershist', v) +is_valid_semver <- function(v) { + .Call('_vershist_is_valid_semver', PACKAGE = 'vershist', v) } diff --git a/R/ios.R b/R/ios.R new file mode 100644 index 0000000..bb61745 --- /dev/null +++ b/R/ios.R @@ -0,0 +1,62 @@ +#' Retrieve Apple iOS Version Release History +#' +#' Reads to build a data +#' frame of Apple iOS version release numbers and dates with pseudo-semantic version +#' strings parsed and separate fields added. The data frame is also arranged in +#' order from lowest version to latest version and the `vers` column is an +#' ordered factor. +#' +#' @md +#' @note This does not distinguish by device target and only pulls the first release +#' date and excludes betas. If more granular data is needed, file an issue or PR. +#' @export +apple_ios_version_history <- function() { + + pg <- xml2::read_html("https://en.wikipedia.org/wiki/IOS_version_history") + + vers_nodes <- rvest::html_nodes(pg, xpath=".//th[contains(@id, '.') or contains(., '.')]") + + dplyr::data_frame( + vers = rvest::html_text(vers_nodes), + rls_date = purrr::map_chr( + vers_nodes, + ~rvest::html_node(.x, xpath=".//following-sibling::td[3]") %>% + rvest::html_text() + ) + ) %>% + dplyr::filter(!stri_detect_regex(vers, "Table|Post|Apple")) %>% + dplyr::mutate(vers = stri_replace_all_regex(vers, "\\[.*\\]", "")) -> xdf + + dplyr::filter(xdf, !stri_detect_fixed(vers, "/")) %>% + dplyr::mutate( + rls_date = stri_extract_first_regex( + rls_date, "[[:alpha:]]{2,}[[:space:]]+[[:digit:]]{1,2},[[:space:]]+[[:digit:]]{4}" + ) + ) -> simple + + more_complex <- dplyr::filter(xdf, stri_detect_fixed(vers, "/")) + + c_v <- stri_extract_all_regex(more_complex$vers, "[[:digit:]\\.]+") + c_d <- stri_extract_all_regex(more_complex$rls_date, "[[:alpha:]]{2,}[[:space:]]+[[:digit:]]{1,2},[[:space:]]+[[:digit:]]{4}") + + purrr::map2_df(c_v, c_d, ~{ + dplyr::data_frame( + vers = .x, + rls_date = .y + ) + }) -> more_complex + + dplyr::bind_rows(simple, more_complex) %>% + dplyr::mutate(rls_date = lubridate::mdy(rls_date)) %>% + dplyr::filter(!stri_detect_fixed(vers, "Beta")) %>% + dplyr::mutate( + vers = ifelse(stri_count_fixed(vers, ".") == 1, sprintf("%s.0", vers), vers) + ) %>% + dplyr::bind_cols( + semver::parse_version(.$vers) %>% + dplyr::as_data_frame() + ) %>% + dplyr::arrange(major, minor, patch) %>% + dplyr::mutate(vers = factor(vers, levels = vers)) + +} \ No newline at end of file diff --git a/R/lighttpd.R b/R/lighttpd.R index 724fc83..84207d4 100644 --- a/R/lighttpd.R +++ b/R/lighttpd.R @@ -3,7 +3,7 @@ #' Reads from the `lighttpd` releases and snapshot downloads to build a #' data frame of version release numbers and dates. The caller is responsible #' for extracting out the version components due to the non-standard -#' semantic versioning used. The [is_valid()] function can be used to test the +#' semantic versioning used. The [is_valid_semver()] function can be used to test the #' validity of version strings. #' #' @md diff --git a/R/utils.R b/R/utils.R new file mode 100644 index 0000000..37ea05e --- /dev/null +++ b/R/utils.R @@ -0,0 +1,34 @@ +#' Turn partial "valid" semantic version strings into a complete semver-tri or quad strings +#' +#' For MAJOR.MINOR.PATCH (semver-tri), turn `1` into `1.0.0`; `1.1` into `1.1.0`; `1.1.1` +#' into `1.1.1`. For MAJOR.MINOR.PATCH.EXTENSION (semver-quad), turn `1` into `1.0.0.0`; +#' `1.1` into `1.1.0.0`; `1.1.1.0` into `1.1.1.0`. +#' +#' Partial validity checking is performed to test if the input strings contain only +#' digits and periods. "Invalid" input is returned unscathed. +#' +#' @param x a character vector of full or partial version strings +#' @param quad (logical) if `TRUE` then a three-dot semver is returned, else a two-dot semver +#' is returned. Default: `FALSE`. +#' @export +complete_semver <- function(x, quad = FALSE) { + + x <- stri_trim_both(x) + x <- stri_replace_all_regex(x, "(^\\.|\\.$)", "") + + max_dots <- if (quad) 3 else 2 + + purrr::map_chr(x, ~{ + if (stri_detect_regex(.x, "^[[:digit:]\\.]+$")) { + times <- max_dots - stri_count_fixed(.x, ".") + if (times > 0) { + sprintf("%s%s", .x, paste0(rep(".0", times), collapse="")) + } else { + .x + } + } else { + .x + } + }) + +} diff --git a/R/vershist-package.R b/R/vershist-package.R index 8c4d2e5..21f728b 100644 --- a/R/vershist-package.R +++ b/R/vershist-package.R @@ -15,6 +15,7 @@ #' @importFrom stringi stri_replace_all_regex stri_replace_first_fixed stri_trans_tolower #' @importFrom stringi stri_extract_first_regex stri_sub stri_replace_first_regex #' @importFrom stringi stri_replace_all_fixed stri_split_fixed stri_count_fixed stri_trim_both +#' @importFrom stringi stri_extract_all_regex #' @importFrom lubridate year mdy mdy_hms parse_date_time #' @importFrom readr read_lines #' @importFrom utils globalVariables diff --git a/README.Rmd b/README.Rmd index 58ca014..7145b7b 100644 --- a/README.Rmd +++ b/README.Rmd @@ -1,5 +1,7 @@ --- output: rmarkdown::github_document +editor_options: + chunk_output_type: console --- # vershist @@ -18,6 +20,7 @@ The following functions are implemented: Core: - `apache_httpd_version_history`: Retrieve Apache httpd Version Release History +- `apple_ios_version_history`: Retrieve Apple iOS Version Release History - `google_chrome_version_history`: Retrieve Google Chrome Version Release History - `lighttpd_version_history`: Retrieve lighttpd Version Release History - `memcached_version_history`: Retrieve memcached Version Release History @@ -31,7 +34,8 @@ Core: Utility: -- `is_valid`: Test if semantic version strings are valid +- `is_valid_semver`: Test if semantic version strings are valid +- `complete_semver`: Turn partial "valid" semantic version strings into a complete semver-tri or quad strings ## Installation @@ -52,12 +56,31 @@ library(vershist) packageVersion("vershist") ``` +Utility + +```{r utility} +versions <- c("steve", "1", "2.1", "3.2.1", "4.3.2.1") + +# Technically, a "valid" semver string is MAJOR.MINOR.PATCH +is_valid_semver(versions) + +complete_semver(versions) + +complete_semver(versions, quad=TRUE) +``` + Apache ```{r apache, cache=TRUE} apache_httpd_version_history() ``` +Apple iOS + +```{r apple_ios, cache=TRUE} +apple_ios_version_history() +``` + Google Chrome ```{r chrome, cache=TRUE} diff --git a/README.md b/README.md index 2b42b7d..6d77a11 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ Core: - `apache_httpd_version_history`: Retrieve Apache httpd Version Release History + - `apple_ios_version_history`: Retrieve Apple iOS Version Release + History - `google_chrome_version_history`: Retrieve Google Chrome Version Release History - `lighttpd_version_history`: Retrieve lighttpd Version Release @@ -34,7 +36,9 @@ Core: Utility: - - `is_valid`: Test if semantic version strings are valid + - `is_valid_semver`: Test if semantic version strings are valid + - `complete_semver`: Turn partial “valid” semantic version strings + into a complete semver-tri or quad strings ## Installation @@ -53,6 +57,29 @@ packageVersion("vershist") ## [1] '0.1.0' +Utility + +``` r +versions <- c("steve", "1", "2.1", "3.2.1", "4.3.2.1") + +# Technically, a "valid" semver string is MAJOR.MINOR.PATCH +is_valid_semver(versions) +``` + + ## [1] FALSE TRUE TRUE TRUE FALSE + +``` r +complete_semver(versions) +``` + + ## [1] "steve" "1.0.0" "2.1.0" "3.2.1" "4.3.2.1" + +``` r +complete_semver(versions, quad=TRUE) +``` + + ## [1] "steve" "1.0.0.0" "2.1.0.0" "3.2.1.0" "4.3.2.1" + Apache ``` r @@ -74,6 +101,27 @@ apache_httpd_version_history() ## 10 1.3.14 2000-10-10 2000 1 3 14 "" "" ## # ... with 19 more rows +Apple iOS + +``` r +apple_ios_version_history() +``` + + ## # A tibble: 112 x 7 + ## vers rls_date major minor patch prerelease build + ## + ## 1 1.0.0 2007-06-29 1 0 0 "" "" + ## 2 1.0.1 2007-07-31 1 0 1 "" "" + ## 3 1.0.2 2007-08-21 1 0 2 "" "" + ## 4 1.1.0 2007-09-14 1 1 0 "" "" + ## 5 1.1.1 2007-09-27 1 1 1 "" "" + ## 6 1.1.2 2007-11-12 1 1 2 "" "" + ## 7 1.1.3 2008-01-15 1 1 3 "" "" + ## 8 1.1.4 2008-02-26 1 1 4 "" "" + ## 9 1.1.5 2008-07-15 1 1 5 "" "" + ## 10 2.0.0 2008-07-11 2 0 0 "" "" + ## # ... with 102 more rows + Google Chrome ``` r diff --git a/README_cache/gfm/apple_ios_c87a0ba8187fd58c6318fd9ff44ca2a6.RData b/README_cache/gfm/apple_ios_c87a0ba8187fd58c6318fd9ff44ca2a6.RData new file mode 100644 index 0000000000000000000000000000000000000000..248474657eb7656a097e3986204c7ccbe66063aa GIT binary patch literal 3034 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 literal 0 HcmV?d00001 diff --git a/README_cache/gfm/apple_ios_c87a0ba8187fd58c6318fd9ff44ca2a6.rdb b/README_cache/gfm/apple_ios_c87a0ba8187fd58c6318fd9ff44ca2a6.rdb new file mode 100644 index 0000000..e69de29 diff --git a/README_cache/gfm/apple_ios_c87a0ba8187fd58c6318fd9ff44ca2a6.rdx b/README_cache/gfm/apple_ios_c87a0ba8187fd58c6318fd9ff44ca2a6.rdx new file mode 100644 index 0000000000000000000000000000000000000000..868ca760ebb3f8872e5987c601b5a50d96d134cb GIT binary patch literal 113 zcmb2|=3oE==1?C;t_B01?$IctP&W&;`2sZohGwV4^ is_valid(std::vector < std::string > v); -RcppExport SEXP _vershist_is_valid(SEXP vSEXP) { +// is_valid_semver +std::vector < bool > is_valid_semver(std::vector < std::string > v); +RcppExport SEXP _vershist_is_valid_semver(SEXP vSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; Rcpp::traits::input_parameter< std::vector < std::string > >::type v(vSEXP); - rcpp_result_gen = Rcpp::wrap(is_valid(v)); + rcpp_result_gen = Rcpp::wrap(is_valid_semver(v)); return rcpp_result_gen; END_RCPP } static const R_CallMethodDef CallEntries[] = { - {"_vershist_is_valid", (DL_FUNC) &_vershist_is_valid, 1}, + {"_vershist_is_valid_semver", (DL_FUNC) &_vershist_is_valid_semver, 1}, {NULL, NULL, 0} }; diff --git a/src/vershist-main.cpp b/src/vershist-main.cpp index ca360e6..b2418b6 100644 --- a/src/vershist-main.cpp +++ b/src/vershist-main.cpp @@ -15,12 +15,12 @@ bool one_is_valid(std::string v) { } -//' Test if semantic version strings are valid +//' Test if semantic version strings are valid tri-string //' //' @param v character verctor of version strings //' @export // [[Rcpp::export]] -std::vector < bool > is_valid(std::vector < std::string > v) { +std::vector < bool > is_valid_semver(std::vector < std::string > v) { std::vector < bool > ret(v.size());