Skip to content

Commit

Permalink
parse_size() now accepts (and rounds down) decimal file sizes, but …
Browse files Browse the repository at this point in the history
…throws

  a warning
  • Loading branch information
s-fleck committed Dec 13, 2020
1 parent 6da063d commit fb6917d
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 83 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Type: Package
Package: rotor
Title: Log Rotation and Conditional Backups
Version: 0.3.4.9000
Version: 0.3.5
Authors@R:
person(given = "Stefan",
family = "Fleck",
Expand Down
4 changes: 3 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# rotor (dev)
# rotor 0.3.5

* Backups now retain their original timestamp (created, last modified) where
possible (even when zipped)
* fixed broken behaviour when pruning with max_backups where max_backups is
the maximum number of files
* `parse_size()` now accepts (and rounds down) decimal file sizes, but throws
a warning

# rotor 0.3.4

Expand Down
20 changes: 12 additions & 8 deletions R/parsers.R
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,20 @@ parse_size <- function(x){
assert(is_scalar(x) && !is.na(x))

if (is_integerish(x)){
return(as.integer(x))
} else {
assert(is.character(x))
}
res <- as.integer(x)
} else if (is.numeric(x)){
res <- as.integer(floor(x))
warning("`x` ist not an integer file size, rounding down to ", res, " bits")

unit_start <- regexec("[kmgt]", tolower(x))[[1]]
} else if (is.character(x)){
unit_start <- regexec("[kmgt]", tolower(x))[[1]]
num <- trimws(substr(x, 1, unit_start - 1L))
unit <- trimws(substr(x, unit_start, nchar(x)))
res <- as.numeric(num) * parse_info_unit(unit)

num <- trimws(substr(x, 1, unit_start - 1L))
unit <- trimws(substr(x, unit_start, nchar(x)))
res <- as.numeric(num) * parse_info_unit(unit)
} else {
stop(ValueError(paste("`x` is not a valid file size but ", preview_object(x))))
}

assert(is_scalar(res) && !is.na(res) && is_scalar_numeric(res))
res
Expand Down
11 changes: 7 additions & 4 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,8 @@ unlink(td, recursive = TRUE)

## Cache

rotor also provides a simple on-disk key-value store that can be used as a
persistent cache.
rotor also provides a simple on-disk key-value store that can be pruned by size,
age or number of files.

```{r}
cache <- Cache$new(file.path(tempdir(), "cache-test"), hashfun = digest::digest)
Expand Down Expand Up @@ -205,10 +205,13 @@ anything outside of base R)

Optional dependencies:

* [digest](https://github.com/eddelbuettel/digest) or
* [digest](https://github.com/eddelbuettel/digest),
[ulid](https://cran.r-project.org/package=ulid), or
[uuid](https://CRAN.R-project.org/package=uuid ) for generating
hashes or UIDs when using Cache. Storage keys for cache files can also be set
hashes or UIDs when using `Cache`. Storage keys for cache files can also be set
manually, in which case no external dependencies are required.
* [zip](https://CRAN.R-project.org/package=zip) is supported as an alternative
to the integrated zip function in R. Might work better on some systems and
worse on others.
* [crayon](https://cran.r-project.org/package=crayon) for
terminal colors
81 changes: 42 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ backup(tf, compression = TRUE)

# display backups of a file
list_backups(tf)
#> [1] "/tmp/Rtmpw73XUg/rotor/mylogfile.1.log.zip"
#> [2] "/tmp/Rtmpw73XUg/rotor/mylogfile.2.log"
#> [1] "/tmp/RtmpRZc2Qd/rotor/mylogfile.1.log.zip"
#> [2] "/tmp/RtmpRZc2Qd/rotor/mylogfile.2.log"
```

`rotate()` also backs up a file, but replaces the original file with an
Expand All @@ -93,9 +93,9 @@ empty one.
``` r
rotate(tf)
list_backups(tf)
#> [1] "/tmp/Rtmpw73XUg/rotor/mylogfile.1.log"
#> [2] "/tmp/Rtmpw73XUg/rotor/mylogfile.2.log.zip"
#> [3] "/tmp/Rtmpw73XUg/rotor/mylogfile.3.log"
#> [1] "/tmp/RtmpRZc2Qd/rotor/mylogfile.1.log"
#> [2] "/tmp/RtmpRZc2Qd/rotor/mylogfile.2.log.zip"
#> [3] "/tmp/RtmpRZc2Qd/rotor/mylogfile.3.log"

# the original file is now empty
readLines(tf)
Expand All @@ -118,10 +118,10 @@ backup(tf, max_backups = 4)
backup(tf, max_backups = 4)

list_backups(tf)
#> [1] "/tmp/Rtmpw73XUg/rotor/mylogfile.1.log"
#> [2] "/tmp/Rtmpw73XUg/rotor/mylogfile.2.log"
#> [3] "/tmp/Rtmpw73XUg/rotor/mylogfile.3.log"
#> [4] "/tmp/Rtmpw73XUg/rotor/mylogfile.4.log.zip"
#> [1] "/tmp/RtmpRZc2Qd/rotor/mylogfile.1.log"
#> [2] "/tmp/RtmpRZc2Qd/rotor/mylogfile.2.log"
#> [3] "/tmp/RtmpRZc2Qd/rotor/mylogfile.3.log"
#> [4] "/tmp/RtmpRZc2Qd/rotor/mylogfile.4.log.zip"
```

We can also use `prune_backups()` to delete old backups. Other than
Expand Down Expand Up @@ -154,29 +154,29 @@ backup_time(tf, format = "%Y%m%dT%H%M%S") # ISO 8601 compatible

backup_info(tf)
#> path name
#> 1 /tmp/Rtmpw73XUg/rotor/mylogfile.2020-07-24_10-54-30.log mylogfile
#> 2 /tmp/Rtmpw73XUg/rotor/mylogfile.2020-07-24--10-54-30.log mylogfile
#> 5 /tmp/Rtmpw73XUg/rotor/mylogfile.20200724T105430.log mylogfile
#> 3 /tmp/Rtmpw73XUg/rotor/mylogfile.2020-07-24.log mylogfile
#> 4 /tmp/Rtmpw73XUg/rotor/mylogfile.2020-07.log mylogfile
#> 1 /tmp/RtmpRZc2Qd/rotor/mylogfile.2020-12-11_20-23-35.log mylogfile
#> 2 /tmp/RtmpRZc2Qd/rotor/mylogfile.2020-12-11--20-23-35.log mylogfile
#> 5 /tmp/RtmpRZc2Qd/rotor/mylogfile.20201211T202335.log mylogfile
#> 3 /tmp/RtmpRZc2Qd/rotor/mylogfile.2020-12-11.log mylogfile
#> 4 /tmp/RtmpRZc2Qd/rotor/mylogfile.2020-12.log mylogfile
#> sfx ext size isdir mode mtime
#> 1 2020-07-24_10-54-30 log 26 FALSE 664 2020-07-24 10:54:30
#> 2 2020-07-24--10-54-30 log 26 FALSE 664 2020-07-24 10:54:30
#> 5 20200724T105430 log 26 FALSE 664 2020-07-24 10:54:30
#> 3 2020-07-24 log 26 FALSE 664 2020-07-24 10:54:30
#> 4 2020-07 log 26 FALSE 664 2020-07-24 10:54:30
#> ctime atime uid gid uname grname
#> 1 2020-07-24 10:54:30 2020-07-24 10:54:30 11861 11861 fleck fleck
#> 2 2020-07-24 10:54:30 2020-07-24 10:54:30 11861 11861 fleck fleck
#> 5 2020-07-24 10:54:30 2020-07-24 10:54:30 11861 11861 fleck fleck
#> 3 2020-07-24 10:54:30 2020-07-24 10:54:30 11861 11861 fleck fleck
#> 4 2020-07-24 10:54:30 2020-07-24 10:54:30 11861 11861 fleck fleck
#> 1 2020-12-11_20-23-35 log 26 FALSE 664 2020-12-11 20:23:35
#> 2 2020-12-11--20-23-35 log 26 FALSE 664 2020-12-11 20:23:35
#> 5 20201211T202335 log 26 FALSE 664 2020-12-11 20:23:35
#> 3 2020-12-11 log 26 FALSE 664 2020-12-11 20:23:35
#> 4 2020-12 log 26 FALSE 664 2020-12-11 20:23:35
#> ctime atime uid gid uname grname
#> 1 2020-12-11 20:23:35 2020-12-11 20:23:35 1000 1000 hoelk hoelk
#> 2 2020-12-11 20:23:35 2020-12-11 20:23:35 1000 1000 hoelk hoelk
#> 5 2020-12-11 20:23:35 2020-12-11 20:23:35 1000 1000 hoelk hoelk
#> 3 2020-12-11 20:23:35 2020-12-11 20:23:35 1000 1000 hoelk hoelk
#> 4 2020-12-11 20:23:35 2020-12-11 20:23:35 1000 1000 hoelk hoelk
#> timestamp
#> 1 2020-07-24 10:54:30
#> 2 2020-07-24 10:54:30
#> 5 2020-07-24 10:54:30
#> 3 2020-07-24 00:00:00
#> 4 2020-07-01 00:00:00
#> 1 2020-12-11 20:23:35
#> 2 2020-12-11 20:23:35
#> 5 2020-12-11 20:23:35
#> 3 2020-12-11 00:00:00
#> 4 2020-12-01 00:00:00
```

If we examine the “timestamp” column in the example above, we see that
Expand All @@ -203,20 +203,20 @@ prune_backups(tf, "2018-04-01")

## Cache

rotor also provides a simple on-disk key-value store that can be used as
a persistent cache.
rotor also provides a simple on-disk key-value store that can be pruned
by size, age or number of files.

``` r
cache <- Cache$new(file.path(tempdir(), "cache-test"), hashfun = digest::digest)
#> creating directory '/tmp/Rtmpw73XUg/cache-test'
#> creating directory '/tmp/RtmpRZc2Qd/cache-test'
key1 <- cache$push(iris)
key2 <- cache$push(cars)
key3 <- cache$push(mtcars)

cache$files$path
#> [1] "/tmp/Rtmpw73XUg/cache-test/d3c5d071001b61a9f6131d3004fd0988"
#> [2] "/tmp/Rtmpw73XUg/cache-test/f98a59010652c8e1ee062ed4c43f648e"
#> [3] "/tmp/Rtmpw73XUg/cache-test/a63c70e73b58d0823ab3bcbd3b543d6f"
#> [1] "/tmp/RtmpRZc2Qd/cache-test/d3c5d071001b61a9f6131d3004fd0988"
#> [2] "/tmp/RtmpRZc2Qd/cache-test/f98a59010652c8e1ee062ed4c43f648e"
#> [3] "/tmp/RtmpRZc2Qd/cache-test/a63c70e73b58d0823ab3bcbd3b543d6f"

head(cache$read(key1))
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
Expand All @@ -229,7 +229,7 @@ head(cache$read(key1))

cache$prune(max_files = 1)
cache$files$path
#> [1] "/tmp/Rtmpw73XUg/cache-test/a63c70e73b58d0823ab3bcbd3b543d6f"
#> [1] "/tmp/RtmpRZc2Qd/cache-test/a63c70e73b58d0823ab3bcbd3b543d6f"
cache$purge() # deletes all cached files
cache$destroy() # deletes the cache directory
```
Expand All @@ -251,11 +251,14 @@ anything outside of base R)

Optional dependencies:

- [digest](https://github.com/eddelbuettel/digest) or
- [digest](https://github.com/eddelbuettel/digest),
[ulid](https://cran.r-project.org/package=ulid), or
[uuid](https://CRAN.R-project.org/package=uuid) for generating
hashes or UIDs when using Cache. Storage keys for cache files can
hashes or UIDs when using `Cache`. Storage keys for cache files can
also be set manually, in which case no external dependencies are
required.
- [zip](https://CRAN.R-project.org/package=zip) is supported as an
alternative to the integrated zip function in R. Might work better
on some systems and worse on others.
- [crayon](https://cran.r-project.org/package=crayon) for terminal
colors
17 changes: 9 additions & 8 deletions cran-comments.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
## Test environments
* ubuntu 20.04, R 4.0.2
* ubuntu 18.04 (via RStudio Server), R 4.0.2
* ubuntu 16.04 (via travis), R 3.6.1
* win-builder, R devel
* macOS 10.13.6 High Sierra, R-release, brew (via Rhub)
* rhub::check_for_cran()
- ubuntu 20.04, R 4.0.2
- ubuntu 18.04 (via RStudio Server), R 4.0.2
- ubuntu 16.04 (via travis), R 3.6.1
- win-builder, R devel
- R-hub ubuntu-gcc-release (r-release)
- R-hub windows-x86_64-devel (r-devel)
- R-hub fedora-clang-devel (r-devel)
- R-hub macos-highsierra-release (r-release)

## R CMD check results

0 errors | 0 warnings | 0 notes

More fixes for file-system timestamp related bugs that I could not reproduce on
my test systems. Sorry again for all the trouble.
Maintenance release with some small bug fixes
25 changes: 11 additions & 14 deletions tests/testthat/test_BackupQueue.R
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,8 @@ test_that("BackupQueue$push() works as expected", {
dir.create(td, recursive = TRUE)
on.exit(unlink(td, recursive = TRUE))

if (!is_zipcmd_available())
skip("Test requires a workings system zip command")
skip_if_not(is_zipcmd_available(), "system zip-command is available")


tf <- file.path(td, "test.log")
file.create(tf)
Expand Down Expand Up @@ -430,8 +430,7 @@ test_that("BackupQueueIndex$push() can push to different directory", {
dir.create(td, recursive = TRUE)
on.exit(unlink(td, recursive = TRUE))

if (!is_zipcmd_available())
skip("Test requires a workings system zip command")
skip_if_not(is_zipcmd_available(), "system zip-command is available")

tf <- file.path(td, "test.log")
bu_dir <- file.path(td, "backups")
Expand Down Expand Up @@ -575,7 +574,7 @@ test_that("BackupQueueIndex: rotations trigger as expected", {
expect_false(bq$should_rotate(size = file.size(tf) + 1))

# size threshold is met
expect_true(bq$should_rotate(size = file.size(tf) / 2))
expect_true(bq$should_rotate(size = round(file.size(tf) / 2)))
})


Expand Down Expand Up @@ -884,8 +883,7 @@ test_that("BackupQueueDateTime$push() can push to different directory", {
dir.create(td, recursive = TRUE)
on.exit(unlink(td, recursive = TRUE))

if (!is_zipcmd_available())
skip("Test requires a workings system zip command")
skip_if_not(is_zipcmd_available(), "system zip-command is available")

tf <- file.path(td, "test.log")
bu_dir <- file.path(td, "backups")
Expand Down Expand Up @@ -978,13 +976,13 @@ test_that("BackupQueueDateTime: rotations trigger as expected", {
expect_false(bq$should_rotate(size = file.size(tf) + 1, age = Inf))

# size threshold is met but not age
expect_false(bq$should_rotate(size = file.size(tf) / 2, age = "2 days", now = as.POSIXct("2020-01-01 02:00:00"), last_rotation = fake_time))
expect_false(bq$should_rotate(size = round(file.size(tf) / 2), age = "2 days", now = as.POSIXct("2020-01-01 02:00:00"), last_rotation = fake_time))

# age threshold is met but not size
expect_false(bq$should_rotate(size = file.size(tf) + 1, age = "2 days", now = as.POSIXct("2020-01-04 02:00:00"), last_rotation = fake_time))

# both criteria are met
expect_true(bq$should_rotate(size = file.size(tf) / 2, age = "2 days", now = as.POSIXct("2020-01-06 02:00:00"), last_rotation = fake_time))
expect_true(bq$should_rotate(size = round(file.size(tf) / 2), age = "2 days", now = as.POSIXct("2020-01-06 02:00:00"), last_rotation = fake_time))
})


Expand Down Expand Up @@ -1268,8 +1266,7 @@ test_that("BackupQueueDateTime$push() can push to different directory", {
dir.create(td, recursive = TRUE)
on.exit(unlink(td, recursive = TRUE))

if (!is_zipcmd_available())
skip("Test requires a workings system zip command")
skip_if_not(is_zipcmd_available(), "system zip-command is available")

tf <- file.path(td, "test.log")
bu_dir <- file.path(td, "backups")
Expand Down Expand Up @@ -1400,13 +1397,13 @@ test_that("BackupQueueDate: rotations trigger as expected", {
expect_false(bq$should_rotate(size = file.size(tf) + 1, age = Inf))

# size threshold is met but not age
expect_false(bq$should_rotate(size = file.size(tf) / 2, age = "2 days", now = as.POSIXct("2020-01-01 02:00:00"), last_rotation = fake_time))
expect_false(bq$should_rotate(size = floor(file.size(tf) / 2), age = "2 days", now = as.POSIXct("2020-01-01 02:00:00"), last_rotation = fake_time))

# age threshold is met but not size
expect_false(bq$should_rotate(size = file.size(tf) + 1, age = "2 days", now = as.POSIXct("2020-01-04 02:00:00"), last_rotation = fake_time))
expect_false(bq$should_rotate(size = round(file.size(tf) + 1), age = "2 days", now = as.POSIXct("2020-01-04 02:00:00"), last_rotation = fake_time))

# both criteria are met
expect_true(bq$should_rotate(size = file.size(tf) / 2, age = "2 days", now = as.POSIXct("2020-01-06 02:00:00"), last_rotation = fake_time))
expect_true(bq$should_rotate(size = floor(file.size(tf) / 2), age = "2 days", now = as.POSIXct("2020-01-06 02:00:00"), last_rotation = fake_time))
})


Expand Down
11 changes: 7 additions & 4 deletions tests/testthat/test_copy_or_compress.R
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ create_testfile <- function(){


test_that("copy_or_compress works with default zip command", {
if (!is_zipcmd_available())
skip("Test requires a workings system zip command")
skip_if_not(is_zipcmd_available(), "system zip-command is available")

tf <- file.path(td, "compresstest.log")
on.exit(unlink(tf))
Expand All @@ -42,8 +41,7 @@ test_that("copy_or_compress works with default zip command", {


test_that("copy_or_compress works with internal zip command", {
if (!is_zipcmd_available())
skip("Test requires a workings system zip command")
skip_if_not(is_zipcmd_available(), "system zip-command is available")

tf <- file.path(td, "compresstest.log")
on.exit(unlink(tf))
Expand All @@ -60,6 +58,7 @@ test_that("copy_or_compress works with internal zip command", {

test_that("copy_or_compress works with zip::zipr", {
skip_if_not_installed("zip")
skip_if_not(is_zipcmd_available(), "system zip-command is available")

tf <- file.path(td, "compresstest.log")
on.exit(unlink(tf))
Expand All @@ -75,6 +74,9 @@ test_that("copy_or_compress works with zip::zipr", {


test_that("copy_or_compress preserves timestamp", {
skip_if_not_installed("zip")
skip_if_not(is_zipcmd_available(), "system zip-command is available")

tf <- create_testfile()
on.exit(unlink(tf))

Expand All @@ -91,3 +93,4 @@ test_that("copy_or_compress preserves timestamp", {
expect_true(equalish(file.mtime(zip), file.mtime(tf), timestamp_tolerance))
})


10 changes: 9 additions & 1 deletion tests/testthat/test_parsers.R
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ test_that("parse_info_unit works", {



test_that("parse_size throws warning when it encounters floats", {
x <- parse_size(18)
expect_warning({y <- parse_size(18.9)})
expect_identical(x, y)
})




test_that("parse_datetime works as expected", {
d <- as.Date("2019-12-01")
expect_equal(parse_datetime(d), as.POSIXct(as.character(d)))
Expand Down Expand Up @@ -114,5 +123,4 @@ test_that("parse_date works as expected", {
expect_equal(parse_date("20190412"), d)
expect_equal(parse_date("201904"), as.Date("2019-04-01"))
expect_equal(parse_date("2019"), as.Date("2019-01-01"))

})
Loading

0 comments on commit fb6917d

Please sign in to comment.