expire 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.reek.yml +23 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +45 -0
  6. data/.simplecov +3 -0
  7. data/.travis.yml +7 -0
  8. data/Gemfile +6 -0
  9. data/Gemfile.lock +152 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +551 -0
  12. data/Rakefile +11 -0
  13. data/bin/console +14 -0
  14. data/bin/setup +8 -0
  15. data/example_rules/bad_rules.yml +2 -0
  16. data/example_rules/good_rules.yml +1 -0
  17. data/exe/expire +7 -0
  18. data/expire.gemspec +54 -0
  19. data/lib/expire.rb +51 -0
  20. data/lib/expire/all_backups_expired_error.rb +7 -0
  21. data/lib/expire/backup.rb +74 -0
  22. data/lib/expire/backup_from_path_service.rb +56 -0
  23. data/lib/expire/backup_list.rb +69 -0
  24. data/lib/expire/cli.rb +221 -0
  25. data/lib/expire/command.rb +122 -0
  26. data/lib/expire/commands/newest.rb +21 -0
  27. data/lib/expire/commands/oldest.rb +21 -0
  28. data/lib/expire/commands/purge.rb +23 -0
  29. data/lib/expire/commands/remove.rb +26 -0
  30. data/lib/expire/commands/rule_classes.rb +18 -0
  31. data/lib/expire/commands/rule_names.rb +20 -0
  32. data/lib/expire/commands/rule_option_names.rb +20 -0
  33. data/lib/expire/from_now_keep_adjective_for_rule_base.rb +38 -0
  34. data/lib/expire/from_now_keep_daily_for_rule.rb +7 -0
  35. data/lib/expire/from_now_keep_hourly_for_rule.rb +7 -0
  36. data/lib/expire/from_now_keep_monthly_for_rule.rb +7 -0
  37. data/lib/expire/from_now_keep_most_recent_for_rule.rb +41 -0
  38. data/lib/expire/from_now_keep_weekly_for_rule.rb +8 -0
  39. data/lib/expire/from_now_keep_yearly_for_rule.rb +8 -0
  40. data/lib/expire/from_range_value.rb +29 -0
  41. data/lib/expire/generate_backup_list_service.rb +45 -0
  42. data/lib/expire/invalid_path_error.rb +7 -0
  43. data/lib/expire/keep_adjective_for_rule_base.rb +34 -0
  44. data/lib/expire/keep_adjective_rule_base.rb +97 -0
  45. data/lib/expire/keep_daily_for_rule.rb +7 -0
  46. data/lib/expire/keep_daily_rule.rb +7 -0
  47. data/lib/expire/keep_hourly_for_rule.rb +7 -0
  48. data/lib/expire/keep_hourly_rule.rb +7 -0
  49. data/lib/expire/keep_monthly_for_rule.rb +7 -0
  50. data/lib/expire/keep_monthly_rule.rb +7 -0
  51. data/lib/expire/keep_most_recent_for_rule.rb +31 -0
  52. data/lib/expire/keep_most_recent_rule.rb +38 -0
  53. data/lib/expire/keep_weekly_for_rule.rb +8 -0
  54. data/lib/expire/keep_weekly_rule.rb +7 -0
  55. data/lib/expire/keep_yearly_for_rule.rb +7 -0
  56. data/lib/expire/keep_yearly_rule.rb +7 -0
  57. data/lib/expire/no_backups_error.rb +7 -0
  58. data/lib/expire/no_rules_error.rb +7 -0
  59. data/lib/expire/numerus_unit.rb +10 -0
  60. data/lib/expire/path_already_exists_error.rb +7 -0
  61. data/lib/expire/playground.rb +62 -0
  62. data/lib/expire/purge_service.rb +91 -0
  63. data/lib/expire/refine_all_and_none.rb +29 -0
  64. data/lib/expire/report_base.rb +23 -0
  65. data/lib/expire/report_enhanced.rb +14 -0
  66. data/lib/expire/report_expired.rb +10 -0
  67. data/lib/expire/report_kept.rb +10 -0
  68. data/lib/expire/report_null.rb +21 -0
  69. data/lib/expire/report_simple.rb +14 -0
  70. data/lib/expire/rule_base.rb +56 -0
  71. data/lib/expire/rule_list.rb +52 -0
  72. data/lib/expire/rules.rb +66 -0
  73. data/lib/expire/templates/newest/.gitkeep +1 -0
  74. data/lib/expire/templates/oldest/.gitkeep +1 -0
  75. data/lib/expire/templates/purge/.gitkeep +1 -0
  76. data/lib/expire/templates/remove/.gitkeep +1 -0
  77. data/lib/expire/templates/rule_classes/.gitkeep +1 -0
  78. data/lib/expire/templates/rule_names/.gitkeep +1 -0
  79. data/lib/expire/templates/rule_option_names/.gitkeep +1 -0
  80. data/lib/expire/unknown_rule_error.rb +10 -0
  81. data/lib/expire/version.rb +9 -0
  82. metadata +321 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e2818cf2a154487c32c4019de8278bc16866d1ca333eba0df45b5abf65859696
4
+ data.tar.gz: fc10fcc4ef4e17800fdda73b4293fd071a1725d9140604e89967299dfca122e5
5
+ SHA512:
6
+ metadata.gz: 0b34e9c57c67bc0ca624b8f8050af4e861b681806804f582e813c0850c153f0078cd60e9f17efafce086433ed0b78ce6f9068e152478db3a3bc926225cef24d3
7
+ data.tar.gz: f6af0819e14453eee1f54623c59d9e10fc549307e0f4b357234c9163cc827bee6a27f7888cf7a879bc60588e65fa269c4d84112fe8699c4b5c8bf6376bdeb7d7
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ /.rbenv-gemsets
14
+ /.ruby-version
15
+ /.byebug_history
data/.reek.yml ADDED
@@ -0,0 +1,23 @@
1
+ ---
2
+ detectors:
3
+ Attribute:
4
+ exclude:
5
+ - Expire::Rules#daily_to_keep
6
+ - Expire::Rules#hourly_to_keep
7
+ - Expire::Rules#monthly_to_keep
8
+ - Expire::Rules#weekly_to_keep
9
+ - Expire::Rules#yearly_to_keep
10
+ TooManyStatements:
11
+ max_statements: 8
12
+ UtilityFunction:
13
+ public_methods_only: true
14
+ UncommunicativeVariableName:
15
+ accept:
16
+ - e
17
+ - _
18
+ directories:
19
+ "lib/expire/commands":
20
+ UnusedParameters:
21
+ enabled: false
22
+ UtilityFunction:
23
+ enabled: false
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,45 @@
1
+ require: rubocop-rspec
2
+
3
+ AllCops:
4
+ Exclude:
5
+ - 'Gemfile'
6
+ - 'Rakefile'
7
+ - 'bin/console'
8
+ - 'expire.gemspec'
9
+ - 'spec/spec_helper.rb'
10
+ NewCops: enable
11
+ SuggestExtensions: false
12
+
13
+ Metrics/BlockLength:
14
+ Exclude:
15
+ - 'spec/**/*'
16
+
17
+ Layout/HashAlignment:
18
+ EnforcedColonStyle: table
19
+
20
+ Naming/VariableNumber:
21
+ EnforcedStyle: snake_case
22
+
23
+ RSpec/DescribeClass:
24
+ Enabled: true
25
+ Exclude:
26
+ - 'spec/integration/*'
27
+
28
+ RSpec/FilePath:
29
+ Enabled: true
30
+ Exclude:
31
+ - 'spec/unit/*'
32
+
33
+ RSpec/ImplicitExpect:
34
+ Enabled: false
35
+
36
+ Lint/MissingSuper:
37
+ Enabled: true
38
+ Exclude:
39
+ - 'lib/expire/*'
40
+ - 'lib/expire/commands/*'
41
+
42
+ Lint/UnusedMethodArgument:
43
+ Enabled: true
44
+ Exclude:
45
+ - lib/expire/commands/*
data/.simplecov ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ SimpleCov.start
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.6
7
+ before_install: gem install bundler -v 1.17.2
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in expire.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,152 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ expire (0.2.0)
5
+ activesupport (~> 6.1)
6
+ pastel (~> 0.8)
7
+ thor (~> 1.1)
8
+ zeitwerk (~> 2.4)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ activesupport (6.1.2.1)
14
+ concurrent-ruby (~> 1.0, >= 1.0.2)
15
+ i18n (>= 1.6, < 2)
16
+ minitest (>= 5.1)
17
+ tzinfo (~> 2.0)
18
+ zeitwerk (~> 2.3)
19
+ aruba (1.0.4)
20
+ childprocess (>= 2.0, < 5.0)
21
+ contracts (~> 0.16.0)
22
+ cucumber (>= 2.4, < 6.0)
23
+ rspec-expectations (~> 3.4)
24
+ thor (~> 1.0)
25
+ ast (2.4.2)
26
+ builder (3.2.4)
27
+ byebug (11.1.3)
28
+ childprocess (4.0.0)
29
+ concurrent-ruby (1.1.8)
30
+ contracts (0.16.0)
31
+ cucumber (5.3.0)
32
+ builder (~> 3.2, >= 3.2.4)
33
+ cucumber-core (~> 8.0, >= 8.0.1)
34
+ cucumber-create-meta (~> 2.0, >= 2.0.2)
35
+ cucumber-cucumber-expressions (~> 10.3, >= 10.3.0)
36
+ cucumber-gherkin (~> 15.0, >= 15.0.2)
37
+ cucumber-html-formatter (~> 9.0, >= 9.0.0)
38
+ cucumber-messages (~> 13.1, >= 13.1.0)
39
+ cucumber-wire (~> 4.0, >= 4.0.1)
40
+ diff-lcs (~> 1.4, >= 1.4.4)
41
+ multi_test (~> 0.1, >= 0.1.2)
42
+ sys-uname (~> 1.2, >= 1.2.1)
43
+ cucumber-core (8.0.1)
44
+ cucumber-gherkin (~> 15.0, >= 15.0.2)
45
+ cucumber-messages (~> 13.0, >= 13.0.1)
46
+ cucumber-tag-expressions (~> 2.0, >= 2.0.4)
47
+ cucumber-create-meta (2.0.4)
48
+ cucumber-messages (~> 13.1, >= 13.1.0)
49
+ sys-uname (~> 1.2, >= 1.2.1)
50
+ cucumber-cucumber-expressions (10.3.0)
51
+ cucumber-gherkin (15.0.2)
52
+ cucumber-messages (~> 13.0, >= 13.0.1)
53
+ cucumber-html-formatter (9.0.0)
54
+ cucumber-messages (~> 13.0, >= 13.0.1)
55
+ cucumber-messages (13.2.1)
56
+ protobuf-cucumber (~> 3.10, >= 3.10.8)
57
+ cucumber-tag-expressions (2.0.4)
58
+ cucumber-wire (4.0.1)
59
+ cucumber-core (~> 8.0, >= 8.0.1)
60
+ cucumber-cucumber-expressions (~> 10.3, >= 10.3.0)
61
+ cucumber-messages (~> 13.0, >= 13.0.1)
62
+ diff-lcs (1.4.4)
63
+ docile (1.3.5)
64
+ ffi (1.14.2)
65
+ i18n (1.8.9)
66
+ concurrent-ruby (~> 1.0)
67
+ kwalify (0.7.2)
68
+ middleware (0.1.0)
69
+ minitest (5.14.3)
70
+ multi_test (0.1.2)
71
+ parallel (1.20.1)
72
+ parser (3.0.0.0)
73
+ ast (~> 2.4.1)
74
+ pastel (0.8.0)
75
+ tty-color (~> 0.5)
76
+ protobuf-cucumber (3.10.8)
77
+ activesupport (>= 3.2)
78
+ middleware
79
+ thor
80
+ thread_safe
81
+ psych (3.3.0)
82
+ rainbow (3.0.0)
83
+ rake (13.0.3)
84
+ reek (6.0.3)
85
+ kwalify (~> 0.7.0)
86
+ parser (~> 3.0.0)
87
+ psych (~> 3.1)
88
+ rainbow (>= 2.0, < 4.0)
89
+ regexp_parser (2.0.3)
90
+ rexml (3.2.4)
91
+ rspec (3.10.0)
92
+ rspec-core (~> 3.10.0)
93
+ rspec-expectations (~> 3.10.0)
94
+ rspec-mocks (~> 3.10.0)
95
+ rspec-core (3.10.1)
96
+ rspec-support (~> 3.10.0)
97
+ rspec-expectations (3.10.1)
98
+ diff-lcs (>= 1.2.0, < 2.0)
99
+ rspec-support (~> 3.10.0)
100
+ rspec-mocks (3.10.2)
101
+ diff-lcs (>= 1.2.0, < 2.0)
102
+ rspec-support (~> 3.10.0)
103
+ rspec-support (3.10.2)
104
+ rubocop (1.10.0)
105
+ parallel (~> 1.10)
106
+ parser (>= 3.0.0.0)
107
+ rainbow (>= 2.2.2, < 4.0)
108
+ regexp_parser (>= 1.8, < 3.0)
109
+ rexml
110
+ rubocop-ast (>= 1.2.0, < 2.0)
111
+ ruby-progressbar (~> 1.7)
112
+ unicode-display_width (>= 1.4.0, < 3.0)
113
+ rubocop-ast (1.4.1)
114
+ parser (>= 2.7.1.5)
115
+ rubocop-rspec (2.2.0)
116
+ rubocop (~> 1.0)
117
+ rubocop-ast (>= 1.1.0)
118
+ ruby-progressbar (1.11.0)
119
+ simplecov (0.21.2)
120
+ docile (~> 1.1)
121
+ simplecov-html (~> 0.11)
122
+ simplecov_json_formatter (~> 0.1)
123
+ simplecov-html (0.12.3)
124
+ simplecov_json_formatter (0.1.2)
125
+ sys-uname (1.2.2)
126
+ ffi (~> 1.1)
127
+ thor (1.1.0)
128
+ thread_safe (0.3.6)
129
+ tty-color (0.6.0)
130
+ tzinfo (2.0.4)
131
+ concurrent-ruby (~> 1.0)
132
+ unicode-display_width (2.0.0)
133
+ zeitwerk (2.4.2)
134
+
135
+ PLATFORMS
136
+ ruby
137
+
138
+ DEPENDENCIES
139
+ aruba (~> 1.0)
140
+ bundler (~> 2.1)
141
+ byebug (~> 11.1)
142
+ cucumber (~> 5.3)
143
+ expire!
144
+ rake (~> 13.0)
145
+ reek (~> 6.0)
146
+ rspec (~> 3.0)
147
+ rubocop (~> 1.9)
148
+ rubocop-rspec (~> 2.2)
149
+ simplecov (~> 0.21)
150
+
151
+ BUNDLED WITH
152
+ 2.2.3
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 TODO: Write your name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,551 @@
1
+ <!-- omit in toc -->
2
+ # Expire
3
+
4
+ **Expire** is a tool for identifying backups that are no longer needed and to delete them.
5
+ It can be used either from the command line or as a ruby gem.
6
+
7
+ <!-- omit in toc -->
8
+ ## Installation
9
+
10
+ **The installation is currently not yet possible!**
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ``` ruby
15
+ gem 'expire'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ ``` shell
21
+ bundle
22
+ ```
23
+
24
+ Or install it yourself as:
25
+
26
+ ``` shell
27
+ gem install expire
28
+ ```
29
+
30
+ - [Usage](#usage)
31
+ - [Purge](#purge)
32
+ - [The `--simulate`, `-s` flag](#the---simulate--s-flag)
33
+ - [The `--format`, `-f` options](#the---format--f-options)
34
+ - [`--format=expired`](#--formatexpired)
35
+ - [`--format=kept`](#--formatkept)
36
+ - [`--format=none`](#--formatnone)
37
+ - [`--format=simple`](#--formatsimple)
38
+ - [`--format=enhanced`](#--formatenhanced)
39
+ - [Rules](#rules)
40
+ - [`--keep-most-recent`](#--keep-most-recent)
41
+ - [`--keep-most-recent-for`](#--keep-most-recent-for)
42
+ - [`--from-now-keep-most-recent-for`](#--from-now-keep-most-recent-for)
43
+ - [Adjectives](#adjectives)
44
+ - [`--keep-<adjective>`](#--keep-adjective)
45
+ - [`--keep-<adjective>-for`](#--keep-adjective-for)
46
+ - [`--from-now-keep-<adjective>-for`](#--from-now-keep-adjective-for)
47
+ - [Time ranges](#time-ranges)
48
+ - [`--rules-file`](#--rules-file)
49
+ - [The `--purge-command`, `--cmd` option](#the---purge-command---cmd-option)
50
+ - [How backup timestamps are detected](#how-backup-timestamps-are-detected)
51
+ - [Newest](#newest)
52
+ - [Oldest](#oldest)
53
+ - [Remove](#remove)
54
+ - [Rule classes](#rule-classes)
55
+ - [Rule names](#rule-names)
56
+ - [Rule option names](#rule-option-names)
57
+ - [Development](#development)
58
+ - [Contributing](#contributing)
59
+ - [License](#license)
60
+
61
+ ## Usage
62
+
63
+ The most important command of `expire` is `purge` which is explained first.
64
+
65
+ ## Purge
66
+
67
+ The `purge` command is used to calculate and delete expired backups.
68
+ It is invoked as follows:
69
+
70
+ ``` shell
71
+ expire path/to/backups <rules>
72
+ ```
73
+
74
+ This would delete, according to the rules, all expired backups under `path/to/backups`.
75
+
76
+ Before deleting, you may want to know what would be removed.
77
+ The `--simulate` option is suitable for this purpose.
78
+
79
+ ### The `--simulate`, `-s` flag
80
+
81
+ To check the expire-rules you can call `expire purge` with the `--simulate` option:
82
+
83
+ ``` shell
84
+ expire path/to/backups <rules> --simulate
85
+ ```
86
+
87
+ When `purge` is called this way it will calculate the expired backups
88
+ but will not delete anything.
89
+
90
+ To see what `purge` would delete you have to specify a format, covered in the following section.
91
+
92
+ ### The `--format`, `-f` options
93
+
94
+ Formats are used to control the output of `expire`.
95
+ `expire` supports various formats.
96
+ The following examples assume a backup-directory containing some backups:
97
+
98
+ ```shell
99
+ backups
100
+ ├── 2016-01-27T1112
101
+ ├── 2019-12-24T1200
102
+ ├── 2021-01-19T1113
103
+ ├── 2021-01-26T1111
104
+ ├── 2021-01-27T1111
105
+ └── 2021-01-27T1112
106
+ ```
107
+
108
+ All `--format`-examples use the `--keep-most-recent=3` rule.
109
+ Rules are explained later in this document.
110
+
111
+ #### `--format=expired`
112
+
113
+ The **expired** format prints the paths of the expired backups, one per line.
114
+
115
+ ```bash
116
+ $ expire purge backups --format=expired --keep-most-recent=3
117
+ backups/2016-01-27T1112
118
+ backups/2019-12-24T1200
119
+ backups/2021-01-19T1113
120
+ ```
121
+
122
+ #### `--format=kept`
123
+
124
+ The **kept** format prints the paths of the kept backups, one per line.
125
+
126
+ ```shell
127
+ $ expire purge backups --format=kept --keep-most-recent=3
128
+ backups/2021-01-26T1111
129
+ backups/2021-01-27T1111
130
+ backups/2021-01-27T1112
131
+ ```
132
+
133
+ #### `--format=none`
134
+
135
+ This is the default format, it prints nothing.
136
+ Nothing is printed here, so no example.
137
+
138
+ #### `--format=simple`
139
+
140
+ The **simple** format prints the path of the kept backups preceded by the work `keeping`
141
+ and the expired backups preceded by the word `purged`.
142
+
143
+ ```bash
144
+ $ expire purge backups --format=simple --keep-most-recent=3
145
+ purged backups/2016-01-27T1112
146
+ purged backups/2019-12-24T1200
147
+ purged backups/2021-01-19T1113
148
+ keeping backups/2021-01-26T1111
149
+ keeping backups/2021-01-27T1111
150
+ keeping backups/2021-01-27T1112
151
+ ```
152
+
153
+ #### `--format=enhanced`
154
+
155
+ The **enhanced** format works the same way as the simple format.
156
+ In addition, it prints the reasons why a backup is kept.
157
+
158
+ ```bash
159
+ $ expire purge backups --format=enhanced --keep-most-recent=3
160
+ purged backups/2016-01-27T1112
161
+ purged backups/2019-12-24T1200
162
+ purged backups/2021-01-19T1113
163
+ keeping backups/2021-01-26T1111
164
+ reasons:
165
+ - keep the 3 most recent backups
166
+ keeping backups/2021-01-27T1111
167
+ reasons:
168
+ - keep the 3 most recent backups
169
+ keeping backups/2021-01-27T1112
170
+ reasons:
171
+ - keep the 3 most recent backups
172
+ ```
173
+
174
+ ### Rules
175
+
176
+ Rules control which backups to keep and which to discard.
177
+ Rules can be specified by command line parameters or in a YAML-file.
178
+
179
+ You must specify at least one rule or `expire purge` will fail.
180
+
181
+ #### `--keep-most-recent`
182
+
183
+ The `--keep-most-recent=3` option preserves the three newest backups from being purged.
184
+
185
+ ```shell
186
+ $ expire purge backups --keep-most-recent 3 --format simple
187
+ purged backups/2016-01-27T1112
188
+ purged backups/2019-12-24T1200
189
+ purged backups/2021-01-19T1113
190
+ keeping backups/2021-01-26T1111
191
+ keeping backups/2021-01-27T1111
192
+ keeping backups/2021-01-27T1112
193
+ ```
194
+
195
+ #### `--keep-most-recent-for`
196
+
197
+ Keeps the newest backups for a **time range** specified by *amount* and *unit*.
198
+ An *amount* is an integer and a unit is something like *days* or *years*.
199
+ Time ranges are discussed in more detail within their own section.
200
+
201
+ The `--keep-most-recent-for "3 years"` option keeps all backups that are not older than three years.
202
+ The **calculation takes the timestamp of the newest backup as reference**.
203
+
204
+ ```shell
205
+ $ expire purge backups --keep-most-recent-for "3 years" --format simple
206
+ purged backups/2016-01-27T1112
207
+ keeping backups/2019-12-24T1200
208
+ keeping backups/2021-01-19T1113
209
+ keeping backups/2021-01-26T1111
210
+ keeping backups/2021-01-27T1111
211
+ keeping backups/2021-01-27T1112
212
+ ```
213
+
214
+ #### `--from-now-keep-most-recent-for`
215
+
216
+ The `--from-now-keep-most-recent-for` option works almost the same way as
217
+ the `--keep-most-recent-for` option does.
218
+ But it **bases its calculation on the current time**, not the timestamp of the newest backup.
219
+
220
+ Assuming today is the 28th January 2021 the option `--from-now-most-recent-for=5.days`
221
+ would act like this:
222
+
223
+ ```shell
224
+ $ expire purge backups --from-now-keep-most-recent-for 5.days --format simple
225
+ purged backups/2016-01-27T1112
226
+ purged backups/2019-12-24T1200
227
+ purged backups/2021-01-19T1113
228
+ keeping backups/2021-01-26T1111
229
+ keeping backups/2021-01-27T1111
230
+ keeping backups/2021-01-27T1112
231
+ ```
232
+
233
+ #### Adjectives
234
+
235
+ The following rules contain an adjective in their name.
236
+ These adjectives are *hourly*, *daily*, *weekly*, *monthly* and *yearly*.
237
+
238
+ #### `--keep-<adjective>`
239
+
240
+ To keep **one backup per time unit** the *adjective rules* are handy.
241
+ There are five adjective rules:
242
+
243
+ - `--keep-hourly`
244
+ - `--keep-daily`
245
+ - `--keep-weekly`
246
+ - `--keep-monthly`
247
+ - `--keep-yearly`
248
+
249
+ All of these expect an integer that specifies the maximum of backups they should preserve.
250
+
251
+ ```shell
252
+ $ expire purge backups --keep-weekly 3 --format=simple
253
+ purged backups/2016-01-27T1112
254
+ keeping backups/2019-12-24T1200
255
+ keeping backups/2021-01-19T1113
256
+ purged backups/2021-01-26T1111
257
+ purged backups/2021-01-27T1111
258
+ keeping backups/2021-01-27T1112
259
+ ```
260
+
261
+ You can also use `all` or `-1` to preserve all backups per time unit.
262
+
263
+ ```shell
264
+ expire purge backups --keep-yearly all --format=simple
265
+ keeping backups/2016-01-27T1112
266
+ keeping backups/2019-12-24T1200
267
+ purged backups/2021-01-19T1113
268
+ purged backups/2021-01-26T1111
269
+ purged backups/2021-01-27T1111
270
+ keeping backups/2021-01-27T1112
271
+ ```
272
+
273
+ #### `--keep-<adjective>-for`
274
+
275
+ To preserve **one backup per unit for a certain time range** you can use *adjective for rules*.
276
+ Time ranges are discussed in more detail within their own section
277
+ There are five *adjective-for* rules:
278
+
279
+ - `--keep-hourly-for`
280
+ - `--keep-daily-for`
281
+ - `--keep-weekly-for`
282
+ - `--keep-monthly-for`
283
+ - `--keep-yearly-for`
284
+
285
+ The **calculation takes the timestamp of the newest backup as reference**.
286
+
287
+ ```shell
288
+ $ expire purge backups --keep-daily-for='3 months' --format=simple
289
+ purged backups/2016-01-27T1112
290
+ purged backups/2019-12-24T1200
291
+ keeping backups/2021-01-19T1113
292
+ keeping backups/2021-01-26T1111
293
+ purged backups/2021-01-27T1111
294
+ keeping backups/2021-01-27T1112
295
+ ```
296
+
297
+ #### `--from-now-keep-<adjective>-for`
298
+
299
+ The *from now adjective for rules* work similar to *adjective for rules*,
300
+ expect they **base their calculations on the current time**, not the timestamp of the newest backup.
301
+
302
+ There are five *from now adjective for rules*:
303
+
304
+ - `--from-now-keep-hourly-for`
305
+ - `--from-now-keep-daily-for`
306
+ - `--from-now-keep-weekly-for`
307
+ - `--from-now-keep-monthly-for`
308
+ - `--from-now-keep-yearly-for`
309
+
310
+ Assuming today is the 28th January 2021 the option `--from-now-most-recent-for=5.days`
311
+ would act like this:
312
+
313
+ ```shell
314
+ $ expire purge backups --from-now-keep-daily-for='3 months' --format=simple
315
+ purged backups/2016-01-27T1112
316
+ purged backups/2019-12-24T1200
317
+ keeping backups/2021-01-19T1113
318
+ keeping backups/2021-01-26T1111
319
+ purged backups/2021-01-27T1111
320
+ keeping backups/2021-01-27T1112
321
+ ```
322
+
323
+ #### Time ranges
324
+
325
+ Some rules take a time range as argument.
326
+ Time ranges can be expressed like this:
327
+
328
+ ```shell
329
+ 1 hour
330
+ 2.weeks
331
+ 3 months
332
+ 1_000 years
333
+ ```
334
+
335
+ As you can see, a range is expressed as a combination of an **integer** and a **unit**.
336
+ The integer portion can include underscores (`_`) **between** the digits.
337
+ Possible values for the unit portion are:
338
+
339
+ - `hour` and `hours`
340
+ - `day` and `days`
341
+ - `week` and `weeks`
342
+ - `moth` and `months`
343
+ - `year` and `years`
344
+
345
+ Units are case-insensitive, so `Year` and `yEaR` are valid too.
346
+
347
+ ### `--rules-file`
348
+
349
+ To read the rules form a YAML-file use the `--rules-file` option.
350
+ The rules have to be specified with an underscore instead of a hyphen.
351
+
352
+ Here is an example rules-file called `rules.yml`:
353
+
354
+ ```yml
355
+ keep_most_recent: 3
356
+ ```
357
+
358
+ With this rules-file we can `expire` with the `--rules-file` option:
359
+
360
+ ```shell
361
+ $ expire purge backups --rules-file rules.yml --format=simple
362
+ purged backups/2016-01-27T1112
363
+ purged backups/2019-12-24T1200
364
+ purged backups/2021-01-19T1113
365
+ keeping backups/2021-01-26T1111
366
+ keeping backups/2021-01-27T1111
367
+ keeping backups/2021-01-27T1112
368
+ ```
369
+
370
+ There is also a shortcut for the `--rules-file` option: `-r`.
371
+
372
+ ### The `--purge-command`, `--cmd` option
373
+
374
+ The `expire` program can remove files and directories,
375
+ but it doesn't know how to deal with logical volumes or subvolumes.
376
+ This is where the `--purge-command` option comes in.
377
+
378
+ The `--purge-command` option takes a command as argument.
379
+ For each expired backup this command is executed with the backup-path as argument.
380
+
381
+ ```shell
382
+ bundle exec exe/expire purge backups --keep-most-recent 3 --format=simple --purge-command='rm -rf'
383
+ purged backups/2016-01-27T1112
384
+ purged backups/2019-12-24T1200
385
+ purged backups/2021-01-19T1113
386
+ keeping backups/2021-01-26T1111
387
+ keeping backups/2021-01-27T1111
388
+ keeping backups/2021-01-27T1112
389
+ ```
390
+
391
+ The previous example has called these shell commands:
392
+
393
+ ```shell
394
+ rm -rf backups/2016-01-27T1112
395
+ rm -rf backups/2019-12-24T1200
396
+ rm -rf backups/2021-01-19T1113
397
+ ```
398
+
399
+ ## How backup timestamps are detected
400
+
401
+ `expire` recognizes the date of a backup by its file name (or directory name).
402
+ This file name must consist of twelve or 14 digits and can optionally contain other characters.
403
+ The digits are considered as `YYYYmmddHHMMSS`, where,
404
+
405
+ - `YYYY` denotes the year of the backup such as `2021`
406
+ - `mm` denotes the month the backups was created such as `01` or `11`
407
+ - `dd` denotes the day of month such as `07` or `28`
408
+ - `HH` denotes the hour (`00`..`23`)
409
+ - `MM` denotes the minute
410
+ - `SS` denotes the second; seconds are optional
411
+
412
+ Some valid filenames:
413
+
414
+ ```shell
415
+ 2021-01-19T1113 # with arbitrary characters
416
+ 2021-01-19T111345 # with arbitrary characters and seconds
417
+ 202101191113 # no arbitrary characters
418
+ 20210119111345 # with seconds and no arbitrary characters
419
+ ```
420
+
421
+ Some **invalid** filenames:
422
+
423
+ ```shell
424
+ 2021-01-19 # just a date, no time
425
+ 2021-02-31T1113 # February 31
426
+ 2101191113 # year 2101, only 10 digits
427
+ 2021011911134501 # 16 digits are too much
428
+ ```
429
+
430
+ Date detection via ctime or mtime is planned for a future release.
431
+
432
+ ## Newest
433
+
434
+ The `newest` command shows the newest backup:
435
+
436
+ ```shell
437
+ $ expire newest backups
438
+ backups/2021-01-27T1112
439
+ ```
440
+
441
+ ## Oldest
442
+
443
+ The `oldest` command shows the oldest backup:
444
+
445
+ ```shell
446
+ $ expire oldest backups
447
+ backups/2016-01-27T1112
448
+ ```
449
+
450
+ ## Remove
451
+
452
+ The `remove` command can be used to remove files or directories:
453
+
454
+ ```shell
455
+ $ expire remove /tmp/stuff
456
+ removed /tmp/stuff
457
+ ```
458
+
459
+ ## Rule classes
460
+
461
+ The `rule-classes` command returns a list of all rule-classes:
462
+
463
+ ```shell
464
+ $ expire rule-classes
465
+ Expire::KeepMostRecentRule
466
+ Expire::KeepMostRecentForRule
467
+ Expire::FromNowKeepMostRecentForRule
468
+ Expire::KeepHourlyRule
469
+ Expire::KeepDailyRule
470
+ Expire::KeepWeeklyRule
471
+ Expire::KeepMonthlyRule
472
+ Expire::KeepYearlyRule
473
+ Expire::KeepHourlyForRule
474
+ Expire::KeepDailyForRule
475
+ Expire::KeepWeeklyForRule
476
+ Expire::KeepMonthlyForRule
477
+ Expire::KeepYearlyForRule
478
+ Expire::FromNowKeepHourlyForRule
479
+ Expire::FromNowKeepDailyForRule
480
+ Expire::FromNowKeepWeeklyForRule
481
+ Expire::FromNowKeepMonthlyForRule
482
+ Expire::FromNowKeepYearlyForRule
483
+ ```
484
+
485
+ ## Rule names
486
+
487
+ The `rule-names` command shows a list of all rule-names:
488
+
489
+ ```shell
490
+ $ expire rule-names
491
+ keep_most_recent
492
+ keep_most_recent_for
493
+ from_now_keep_most_recent_for
494
+ keep_hourly
495
+ keep_daily
496
+ keep_weekly
497
+ keep_monthly
498
+ keep_yearly
499
+ keep_hourly_for
500
+ keep_daily_for
501
+ keep_weekly_for
502
+ keep_monthly_for
503
+ keep_yearly_for
504
+ from_now_keep_hourly_for
505
+ from_now_keep_daily_for
506
+ from_now_keep_weekly_for
507
+ from_now_keep_monthly_for
508
+ from_now_keep_yearly_for
509
+ ```
510
+
511
+ ## Rule option names
512
+
513
+ To get a list of all rule option-names call:
514
+
515
+ ```shell
516
+ $ expire rule-option-names
517
+ --keep-most-recent
518
+ --keep-most-recent-for
519
+ --from-now-keep-most-recent-for
520
+ --keep-hourly
521
+ --keep-daily
522
+ --keep-weekly
523
+ --keep-monthly
524
+ --keep-yearly
525
+ --keep-hourly-for
526
+ --keep-daily-for
527
+ --keep-weekly-for
528
+ --keep-monthly-for
529
+ --keep-yearly-for
530
+ --from-now-keep-hourly-for
531
+ --from-now-keep-daily-for
532
+ --from-now-keep-weekly-for
533
+ --from-now-keep-monthly-for
534
+ --from-now-keep-yearly-for
535
+ ```
536
+
537
+ ## Development
538
+
539
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
540
+
541
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
542
+
543
+ ## Contributing
544
+
545
+ Bug reports and pull requests are welcome on
546
+ GitHub at [thomasregnet/expire](https://github.com/thomasregnet/expire.)
547
+
548
+ ## License
549
+
550
+ The gem is available as open source under the terms of the
551
+ [MIT License](https://opensource.org/licenses/MIT).