expire 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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).