Skip to content

Commit fb6917d

Browse files
committed
parse_size() now accepts (and rounds down) decimal file sizes, but throws
a warning
1 parent 6da063d commit fb6917d

File tree

11 files changed

+103
-83
lines changed

11 files changed

+103
-83
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Type: Package
22
Package: rotor
33
Title: Log Rotation and Conditional Backups
4-
Version: 0.3.4.9000
4+
Version: 0.3.5
55
Authors@R:
66
person(given = "Stefan",
77
family = "Fleck",

NEWS.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
# rotor (dev)
1+
# rotor 0.3.5
22

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

810
# rotor 0.3.4
911

R/parsers.R

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@ parse_size <- function(x){
77
assert(is_scalar(x) && !is.na(x))
88

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

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

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

2125
assert(is_scalar(res) && !is.na(res) && is_scalar_numeric(res))
2226
res

README.Rmd

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ unlink(td, recursive = TRUE)
166166

167167
## Cache
168168

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

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

206206
Optional dependencies:
207207

208-
* [digest](https://github.com/eddelbuettel/digest) or
208+
* [digest](https://github.com/eddelbuettel/digest),
209+
[ulid](https://cran.r-project.org/package=ulid), or
209210
[uuid](https://CRAN.R-project.org/package=uuid ) for generating
210-
hashes or UIDs when using Cache. Storage keys for cache files can also be set
211+
hashes or UIDs when using `Cache`. Storage keys for cache files can also be set
211212
manually, in which case no external dependencies are required.
212213
* [zip](https://CRAN.R-project.org/package=zip) is supported as an alternative
213214
to the integrated zip function in R. Might work better on some systems and
214215
worse on others.
216+
* [crayon](https://cran.r-project.org/package=crayon) for
217+
terminal colors

README.md

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ backup(tf, compression = TRUE)
8383

8484
# display backups of a file
8585
list_backups(tf)
86-
#> [1] "/tmp/Rtmpw73XUg/rotor/mylogfile.1.log.zip"
87-
#> [2] "/tmp/Rtmpw73XUg/rotor/mylogfile.2.log"
86+
#> [1] "/tmp/RtmpRZc2Qd/rotor/mylogfile.1.log.zip"
87+
#> [2] "/tmp/RtmpRZc2Qd/rotor/mylogfile.2.log"
8888
```
8989

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

100100
# the original file is now empty
101101
readLines(tf)
@@ -118,10 +118,10 @@ backup(tf, max_backups = 4)
118118
backup(tf, max_backups = 4)
119119

120120
list_backups(tf)
121-
#> [1] "/tmp/Rtmpw73XUg/rotor/mylogfile.1.log"
122-
#> [2] "/tmp/Rtmpw73XUg/rotor/mylogfile.2.log"
123-
#> [3] "/tmp/Rtmpw73XUg/rotor/mylogfile.3.log"
124-
#> [4] "/tmp/Rtmpw73XUg/rotor/mylogfile.4.log.zip"
121+
#> [1] "/tmp/RtmpRZc2Qd/rotor/mylogfile.1.log"
122+
#> [2] "/tmp/RtmpRZc2Qd/rotor/mylogfile.2.log"
123+
#> [3] "/tmp/RtmpRZc2Qd/rotor/mylogfile.3.log"
124+
#> [4] "/tmp/RtmpRZc2Qd/rotor/mylogfile.4.log.zip"
125125
```
126126

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

155155
backup_info(tf)
156156
#> path name
157-
#> 1 /tmp/Rtmpw73XUg/rotor/mylogfile.2020-07-24_10-54-30.log mylogfile
158-
#> 2 /tmp/Rtmpw73XUg/rotor/mylogfile.2020-07-24--10-54-30.log mylogfile
159-
#> 5 /tmp/Rtmpw73XUg/rotor/mylogfile.20200724T105430.log mylogfile
160-
#> 3 /tmp/Rtmpw73XUg/rotor/mylogfile.2020-07-24.log mylogfile
161-
#> 4 /tmp/Rtmpw73XUg/rotor/mylogfile.2020-07.log mylogfile
157+
#> 1 /tmp/RtmpRZc2Qd/rotor/mylogfile.2020-12-11_20-23-35.log mylogfile
158+
#> 2 /tmp/RtmpRZc2Qd/rotor/mylogfile.2020-12-11--20-23-35.log mylogfile
159+
#> 5 /tmp/RtmpRZc2Qd/rotor/mylogfile.20201211T202335.log mylogfile
160+
#> 3 /tmp/RtmpRZc2Qd/rotor/mylogfile.2020-12-11.log mylogfile
161+
#> 4 /tmp/RtmpRZc2Qd/rotor/mylogfile.2020-12.log mylogfile
162162
#> sfx ext size isdir mode mtime
163-
#> 1 2020-07-24_10-54-30 log 26 FALSE 664 2020-07-24 10:54:30
164-
#> 2 2020-07-24--10-54-30 log 26 FALSE 664 2020-07-24 10:54:30
165-
#> 5 20200724T105430 log 26 FALSE 664 2020-07-24 10:54:30
166-
#> 3 2020-07-24 log 26 FALSE 664 2020-07-24 10:54:30
167-
#> 4 2020-07 log 26 FALSE 664 2020-07-24 10:54:30
168-
#> ctime atime uid gid uname grname
169-
#> 1 2020-07-24 10:54:30 2020-07-24 10:54:30 11861 11861 fleck fleck
170-
#> 2 2020-07-24 10:54:30 2020-07-24 10:54:30 11861 11861 fleck fleck
171-
#> 5 2020-07-24 10:54:30 2020-07-24 10:54:30 11861 11861 fleck fleck
172-
#> 3 2020-07-24 10:54:30 2020-07-24 10:54:30 11861 11861 fleck fleck
173-
#> 4 2020-07-24 10:54:30 2020-07-24 10:54:30 11861 11861 fleck fleck
163+
#> 1 2020-12-11_20-23-35 log 26 FALSE 664 2020-12-11 20:23:35
164+
#> 2 2020-12-11--20-23-35 log 26 FALSE 664 2020-12-11 20:23:35
165+
#> 5 20201211T202335 log 26 FALSE 664 2020-12-11 20:23:35
166+
#> 3 2020-12-11 log 26 FALSE 664 2020-12-11 20:23:35
167+
#> 4 2020-12 log 26 FALSE 664 2020-12-11 20:23:35
168+
#> ctime atime uid gid uname grname
169+
#> 1 2020-12-11 20:23:35 2020-12-11 20:23:35 1000 1000 hoelk hoelk
170+
#> 2 2020-12-11 20:23:35 2020-12-11 20:23:35 1000 1000 hoelk hoelk
171+
#> 5 2020-12-11 20:23:35 2020-12-11 20:23:35 1000 1000 hoelk hoelk
172+
#> 3 2020-12-11 20:23:35 2020-12-11 20:23:35 1000 1000 hoelk hoelk
173+
#> 4 2020-12-11 20:23:35 2020-12-11 20:23:35 1000 1000 hoelk hoelk
174174
#> timestamp
175-
#> 1 2020-07-24 10:54:30
176-
#> 2 2020-07-24 10:54:30
177-
#> 5 2020-07-24 10:54:30
178-
#> 3 2020-07-24 00:00:00
179-
#> 4 2020-07-01 00:00:00
175+
#> 1 2020-12-11 20:23:35
176+
#> 2 2020-12-11 20:23:35
177+
#> 5 2020-12-11 20:23:35
178+
#> 3 2020-12-11 00:00:00
179+
#> 4 2020-12-01 00:00:00
180180
```
181181

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

204204
## Cache
205205

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

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

216216
cache$files$path
217-
#> [1] "/tmp/Rtmpw73XUg/cache-test/d3c5d071001b61a9f6131d3004fd0988"
218-
#> [2] "/tmp/Rtmpw73XUg/cache-test/f98a59010652c8e1ee062ed4c43f648e"
219-
#> [3] "/tmp/Rtmpw73XUg/cache-test/a63c70e73b58d0823ab3bcbd3b543d6f"
217+
#> [1] "/tmp/RtmpRZc2Qd/cache-test/d3c5d071001b61a9f6131d3004fd0988"
218+
#> [2] "/tmp/RtmpRZc2Qd/cache-test/f98a59010652c8e1ee062ed4c43f648e"
219+
#> [3] "/tmp/RtmpRZc2Qd/cache-test/a63c70e73b58d0823ab3bcbd3b543d6f"
220220

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

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

252252
Optional dependencies:
253253

254-
- [digest](https://github.com/eddelbuettel/digest) or
254+
- [digest](https://github.com/eddelbuettel/digest),
255+
[ulid](https://cran.r-project.org/package=ulid), or
255256
[uuid](https://CRAN.R-project.org/package=uuid) for generating
256-
hashes or UIDs when using Cache. Storage keys for cache files can
257+
hashes or UIDs when using `Cache`. Storage keys for cache files can
257258
also be set manually, in which case no external dependencies are
258259
required.
259260
- [zip](https://CRAN.R-project.org/package=zip) is supported as an
260261
alternative to the integrated zip function in R. Might work better
261262
on some systems and worse on others.
263+
- [crayon](https://cran.r-project.org/package=crayon) for terminal
264+
colors

cran-comments.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
## Test environments
2-
* ubuntu 20.04, R 4.0.2
3-
* ubuntu 18.04 (via RStudio Server), R 4.0.2
4-
* ubuntu 16.04 (via travis), R 3.6.1
5-
* win-builder, R devel
6-
* macOS 10.13.6 High Sierra, R-release, brew (via Rhub)
7-
* rhub::check_for_cran()
2+
- ubuntu 20.04, R 4.0.2
3+
- ubuntu 18.04 (via RStudio Server), R 4.0.2
4+
- ubuntu 16.04 (via travis), R 3.6.1
5+
- win-builder, R devel
6+
- R-hub ubuntu-gcc-release (r-release)
7+
- R-hub windows-x86_64-devel (r-devel)
8+
- R-hub fedora-clang-devel (r-devel)
9+
- R-hub macos-highsierra-release (r-release)
810

911
## R CMD check results
1012

1113
0 errors | 0 warnings | 0 notes
1214

13-
More fixes for file-system timestamp related bugs that I could not reproduce on
14-
my test systems. Sorry again for all the trouble.
15+
Maintenance release with some small bug fixes

tests/testthat/test_BackupQueue.R

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,8 @@ test_that("BackupQueue$push() works as expected", {
397397
dir.create(td, recursive = TRUE)
398398
on.exit(unlink(td, recursive = TRUE))
399399

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

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

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

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

577576
# size threshold is met
578-
expect_true(bq$should_rotate(size = file.size(tf) / 2))
577+
expect_true(bq$should_rotate(size = round(file.size(tf) / 2)))
579578
})
580579

581580

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

887-
if (!is_zipcmd_available())
888-
skip("Test requires a workings system zip command")
886+
skip_if_not(is_zipcmd_available(), "system zip-command is available")
889887

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

980978
# size threshold is met but not age
981-
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))
979+
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))
982980

983981
# age threshold is met but not size
984982
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))
985983

986984
# both criteria are met
987-
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))
985+
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))
988986
})
989987

990988

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

1271-
if (!is_zipcmd_available())
1272-
skip("Test requires a workings system zip command")
1269+
skip_if_not(is_zipcmd_available(), "system zip-command is available")
12731270

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

14021399
# size threshold is met but not age
1403-
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))
1400+
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))
14041401

14051402
# age threshold is met but not size
1406-
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))
1403+
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))
14071404

14081405
# both criteria are met
1409-
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))
1406+
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))
14101407
})
14111408

14121409

tests/testthat/test_copy_or_compress.R

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ create_testfile <- function(){
2525

2626

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

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

4342

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

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

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

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

7675

7776
test_that("copy_or_compress preserves timestamp", {
77+
skip_if_not_installed("zip")
78+
skip_if_not(is_zipcmd_available(), "system zip-command is available")
79+
7880
tf <- create_testfile()
7981
on.exit(unlink(tf))
8082

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

96+

tests/testthat/test_parsers.R

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ test_that("parse_info_unit works", {
3939

4040

4141

42+
test_that("parse_size throws warning when it encounters floats", {
43+
x <- parse_size(18)
44+
expect_warning({y <- parse_size(18.9)})
45+
expect_identical(x, y)
46+
})
47+
48+
49+
50+
4251
test_that("parse_datetime works as expected", {
4352
d <- as.Date("2019-12-01")
4453
expect_equal(parse_datetime(d), as.POSIXct(as.character(d)))
@@ -114,5 +123,4 @@ test_that("parse_date works as expected", {
114123
expect_equal(parse_date("20190412"), d)
115124
expect_equal(parse_date("201904"), as.Date("2019-04-01"))
116125
expect_equal(parse_date("2019"), as.Date("2019-01-01"))
117-
118126
})

0 commit comments

Comments
 (0)