Expire
Expire is a tool for identifying backups that are no longer needed and to delete them. It can be used either from the command line or as a ruby gem.
Installation
Add this line to your application's Gemfile:
gem 'expire'And then execute:
bundleOr install it yourself as:
gem install expire- Usage
- Purge
- The
--simulate,-sflag - The
--format,-foptions--format=expired--format=kept--format=none--format=simple--format=enhanced
- Rules
--keep-most-recent--keep-most-recent-for--from-now-keep-most-recent-for- Adjectives
--keep-<adjective>--keep-<adjective>-for--from-now-keep-<adjective>-for- Time ranges
--rules-file- The
--purge-command,--cmdoption
- The
- How backup timestamps are detected
- Newest
- Oldest
- Remove
- Rule classes
- Rule names
- Rule option names
- Development
- Contributing
- License
Usage
The most important command of expire is purge which is explained first.
Purge
The purge command is used to calculate and delete expired backups.
It is invoked as follows:
expire purge path/to/backups <rules>This would delete, according to the rules, all expired backups under path/to/backups.
Before deleting, you may want to know what would be removed.
The --simulate option is suitable for this purpose.
The --simulate, -s flag
To check the expire-rules you can call expire purge with the --simulate option:
expire purge path/to/backups <rules> --simulateWhen purge is called this way it will calculate the expired backups
but will not delete anything.
To see what purge would delete you have to specify a format, covered in the following section.
The --format, -f options
Formats are used to control the output of expire.
expire supports various formats.
The following examples assume a backup-directory containing some backups:
backups
├── 2016-01-27T1112
├── 2019-12-24T1200
├── 2021-01-19T1113
├── 2021-01-26T1111
├── 2021-01-27T1111
└── 2021-01-27T1112All --format-examples use the --keep-most-recent=3 rule.
Rules are explained later in this document.
--format=expired
The expired format prints the paths of the expired backups, one per line.
$ expire purge backups --format=expired --keep-most-recent=3
backups/2016-01-27T1112
backups/2019-12-24T1200
backups/2021-01-19T1113--format=kept
The kept format prints the paths of the kept backups, one per line.
$ expire purge backups --format=kept --keep-most-recent=3
backups/2021-01-26T1111
backups/2021-01-27T1111
backups/2021-01-27T1112--format=none
This is the default format, it prints nothing. Nothing is printed here, so no example.
--format=simple
The simple format prints the path of the kept backups preceded by the work keeping
and the expired backups preceded by the word purged.
$ expire purge backups --format=simple --keep-most-recent=3
purged backups/2016-01-27T1112
purged backups/2019-12-24T1200
purged backups/2021-01-19T1113
keeping backups/2021-01-26T1111
keeping backups/2021-01-27T1111
keeping backups/2021-01-27T1112--format=enhanced
The enhanced format works the same way as the simple format. In addition, it prints the reasons why a backup is kept.
$ expire purge backups --format=enhanced --keep-most-recent=3
purged backups/2016-01-27T1112
purged backups/2019-12-24T1200
purged backups/2021-01-19T1113
keeping backups/2021-01-26T1111
reasons:
- keep the 3 most recent backups
keeping backups/2021-01-27T1111
reasons:
- keep the 3 most recent backups
keeping backups/2021-01-27T1112
reasons:
- keep the 3 most recent backupsRules
Rules control which backups to keep and which to discard. Rules can be specified by command line parameters or in a YAML-file.
You must specify at least one rule or expire purge will fail.
--keep-most-recent
The --keep-most-recent=3 option preserves the three newest backups from being purged.
$ expire purge backups --keep-most-recent 3 --format simple
purged backups/2016-01-27T1112
purged backups/2019-12-24T1200
purged backups/2021-01-19T1113
keeping backups/2021-01-26T1111
keeping backups/2021-01-27T1111
keeping backups/2021-01-27T1112--keep-most-recent-for
Keeps the newest backups for a time range specified by amount and unit. An amount is an integer and a unit is something like days or years. Time ranges are discussed in more detail within their own section.
The --keep-most-recent-for "3 years" option keeps all backups that are not older than three years.
The calculation takes the timestamp of the newest backup as reference.
$ expire purge backups --keep-most-recent-for "3 years" --format simple
purged backups/2016-01-27T1112
keeping backups/2019-12-24T1200
keeping backups/2021-01-19T1113
keeping backups/2021-01-26T1111
keeping backups/2021-01-27T1111
keeping backups/2021-01-27T1112--from-now-keep-most-recent-for
The --from-now-keep-most-recent-for option works almost the same way as
the --keep-most-recent-for option does.
But it bases its calculation on the current time, not the timestamp of the newest backup.
Assuming today is the 28th January 2021 the option --from-now-most-recent-for=5.days
would act like this:
$ expire purge backups --from-now-keep-most-recent-for 5.days --format simple
purged backups/2016-01-27T1112
purged backups/2019-12-24T1200
purged backups/2021-01-19T1113
keeping backups/2021-01-26T1111
keeping backups/2021-01-27T1111
keeping backups/2021-01-27T1112Adjectives
The following rules contain an adjective in their name. These adjectives are hourly, daily, weekly, monthly and yearly.
--keep-<adjective>
To keep one backup per time unit the adjective rules are handy. There are five adjective rules:
--keep-hourly--keep-daily--keep-weekly--keep-monthly--keep-yearly
All of these expect an integer that specifies the maximum of backups they should preserve.
$ expire purge backups --keep-weekly 3 --format=simple
purged backups/2016-01-27T1112
keeping backups/2019-12-24T1200
keeping backups/2021-01-19T1113
purged backups/2021-01-26T1111
purged backups/2021-01-27T1111
keeping backups/2021-01-27T1112You can also use all or -1 to preserve all backups per time unit.
expire purge backups --keep-yearly all --format=simple
keeping backups/2016-01-27T1112
keeping backups/2019-12-24T1200
purged backups/2021-01-19T1113
purged backups/2021-01-26T1111
purged backups/2021-01-27T1111
keeping backups/2021-01-27T1112--keep-<adjective>-for
To preserve one backup per unit for a certain time range you can use adjective for rules. Time ranges are discussed in more detail within their own section There are five adjective-for rules:
--keep-hourly-for--keep-daily-for--keep-weekly-for--keep-monthly-for--keep-yearly-for
The calculation takes the timestamp of the newest backup as reference.
$ expire purge backups --keep-daily-for='3 months' --format=simple
purged backups/2016-01-27T1112
purged backups/2019-12-24T1200
keeping backups/2021-01-19T1113
keeping backups/2021-01-26T1111
purged backups/2021-01-27T1111
keeping backups/2021-01-27T1112--from-now-keep-<adjective>-for
The from now adjective for rules work similar to adjective for rules, expect they base their calculations on the current time, not the timestamp of the newest backup.
There are five from now adjective for rules:
--from-now-keep-hourly-for--from-now-keep-daily-for--from-now-keep-weekly-for--from-now-keep-monthly-for--from-now-keep-yearly-for
Assuming today is the 28th January 2021 the option --from-now-most-recent-for=5.days
would act like this:
$ expire purge backups --from-now-keep-daily-for='3 months' --format=simple
purged backups/2016-01-27T1112
purged backups/2019-12-24T1200
keeping backups/2021-01-19T1113
keeping backups/2021-01-26T1111
purged backups/2021-01-27T1111
keeping backups/2021-01-27T1112Time ranges
Some rules take a time range as argument. Time ranges can be expressed like this:
1 hour
2.weeks
3 months
1_000 yearsAs you can see, a range is expressed as a combination of an integer and a unit.
The integer portion can include underscores (_) between the digits.
Possible values for the unit portion are:
-
hourandhours -
dayanddays -
weekandweeks -
mothandmonths -
yearandyears
Units are case-insensitive, so Year and yEaR are valid too.
--rules-file
To read the rules form a YAML-file use the --rules-file option.
The rules have to be specified with an underscore instead of a hyphen.
Here is an example rules-file called rules.yml:
keep_most_recent: 3With this rules-file we can expire with the --rules-file option:
$ expire purge backups --rules-file rules.yml --format=simple
purged backups/2016-01-27T1112
purged backups/2019-12-24T1200
purged backups/2021-01-19T1113
keeping backups/2021-01-26T1111
keeping backups/2021-01-27T1111
keeping backups/2021-01-27T1112There is also a shortcut for the --rules-file option: -r.
The --purge-command, --cmd option
The expire program can remove files and directories,
but it doesn't know how to deal with logical volumes or subvolumes.
This is where the --purge-command option comes in.
The --purge-command option takes a command as argument.
For each expired backup this command is executed with the backup-path as argument.
bundle exec exe/expire purge backups --keep-most-recent 3 --format=simple --purge-command='rm -rf'
purged backups/2016-01-27T1112
purged backups/2019-12-24T1200
purged backups/2021-01-19T1113
keeping backups/2021-01-26T1111
keeping backups/2021-01-27T1111
keeping backups/2021-01-27T1112The previous example has called these shell commands:
rm -rf backups/2016-01-27T1112
rm -rf backups/2019-12-24T1200
rm -rf backups/2021-01-19T1113How backup timestamps are detected
expire recognizes the date of a backup by its file name (or directory name).
This file name must consist of twelve or 14 digits and can optionally contain other characters.
The digits are considered as YYYYmmddHHMMSS, where,
-
YYYYdenotes the year of the backup such as2021 -
mmdenotes the month the backups was created such as01or11 -
dddenotes the day of month such as07or28 -
HHdenotes the hour (00..23) -
MMdenotes the minute -
SSdenotes the second; seconds are optional
Some valid filenames:
2021-01-19T1113 # with arbitrary characters
2021-01-19T111345 # with arbitrary characters and seconds
202101191113 # no arbitrary characters
20210119111345 # with seconds and no arbitrary charactersSome invalid filenames:
2021-01-19 # just a date, no time
2021-02-31T1113 # February 31
2101191113 # year 2101, only 10 digits
2021011911134501 # 16 digits are too muchNewest
The newest command shows the newest backup:
$ expire newest backups
backups/2021-01-27T1112Oldest
The oldest command shows the oldest backup:
$ expire oldest backups
backups/2016-01-27T1112Remove
The remove command can be used to remove files or directories:
$ expire remove /tmp/stuff
removed /tmp/stuffRule classes
The rule-classes command returns a list of all rule-classes:
$ expire rule-classes
Expire::KeepMostRecentRule
Expire::KeepMostRecentForRule
Expire::FromNowKeepMostRecentForRule
Expire::KeepHourlyRule
Expire::KeepDailyRule
Expire::KeepWeeklyRule
Expire::KeepMonthlyRule
Expire::KeepYearlyRule
Expire::KeepHourlyForRule
Expire::KeepDailyForRule
Expire::KeepWeeklyForRule
Expire::KeepMonthlyForRule
Expire::KeepYearlyForRule
Expire::FromNowKeepHourlyForRule
Expire::FromNowKeepDailyForRule
Expire::FromNowKeepWeeklyForRule
Expire::FromNowKeepMonthlyForRule
Expire::FromNowKeepYearlyForRuleRule names
The rule-names command shows a list of all rule-names:
$ expire rule-names
keep_most_recent
keep_most_recent_for
from_now_keep_most_recent_for
keep_hourly
keep_daily
keep_weekly
keep_monthly
keep_yearly
keep_hourly_for
keep_daily_for
keep_weekly_for
keep_monthly_for
keep_yearly_for
from_now_keep_hourly_for
from_now_keep_daily_for
from_now_keep_weekly_for
from_now_keep_monthly_for
from_now_keep_yearly_forRule option names
To get a list of all rule option-names call:
$ expire rule-option-names
--keep-most-recent
--keep-most-recent-for
--from-now-keep-most-recent-for
--keep-hourly
--keep-daily
--keep-weekly
--keep-monthly
--keep-yearly
--keep-hourly-for
--keep-daily-for
--keep-weekly-for
--keep-monthly-for
--keep-yearly-for
--from-now-keep-hourly-for
--from-now-keep-daily-for
--from-now-keep-weekly-for
--from-now-keep-monthly-for
--from-now-keep-yearly-forDevelopment
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.
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.
Contributing
Bug reports and pull requests are welcome on GitHub at thomasregnet/expire
License
The gem is available as open source under the terms of the MIT License.