mirror of
https://github.com/borgbackup/borg.git
synced 2025-03-04 02:28:34 +00:00
Purge improvements: New options yearly and prefix
This commit is contained in:
parent
e0615df187
commit
9feef66d4e
3 changed files with 35 additions and 10 deletions
|
@ -43,7 +43,9 @@ class Archive(object):
|
||||||
except self.store.DoesNotExist:
|
except self.store.DoesNotExist:
|
||||||
raise self.DoesNotExist
|
raise self.DoesNotExist
|
||||||
self.metadata = msgpack.unpackb(data)
|
self.metadata = msgpack.unpackb(data)
|
||||||
assert self.metadata['version'] == 1
|
if self.metadata['version'] != 1:
|
||||||
|
raise Exception('Unknown archive metadata version')
|
||||||
|
self.name = self.metadata['name']
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ts(self):
|
def ts(self):
|
||||||
|
|
|
@ -11,7 +11,7 @@ from .cache import Cache
|
||||||
from .key import Key
|
from .key import Key
|
||||||
from .helpers import location_validator, format_file_size, format_time,\
|
from .helpers import location_validator, format_file_size, format_time,\
|
||||||
format_file_mode, IncludePattern, ExcludePattern, exclude_path, to_localtime, \
|
format_file_mode, IncludePattern, ExcludePattern, exclude_path, to_localtime, \
|
||||||
get_cache_dir
|
get_cache_dir, day_of_year
|
||||||
from .remote import StoreServer, RemoteStore
|
from .remote import StoreServer, RemoteStore
|
||||||
|
|
||||||
class Archiver(object):
|
class Archiver(object):
|
||||||
|
@ -224,31 +224,39 @@ class Archiver(object):
|
||||||
num_daily = args.daily
|
num_daily = args.daily
|
||||||
num_weekly = args.weekly
|
num_weekly = args.weekly
|
||||||
num_monthly = args.monthly
|
num_monthly = args.monthly
|
||||||
if args.daily + args.weekly + args.monthly == 0:
|
num_yearly = args.yearly
|
||||||
self.print_error('At least one of the "daily", "weekly", "monthly" '
|
if args.daily + args.weekly + args.monthly + args.yearly == 0:
|
||||||
|
self.print_error('At least one of the "daily", "weekly", "monthly" or "yearly" '
|
||||||
'settings must be specified')
|
'settings must be specified')
|
||||||
return 1
|
return 1
|
||||||
t0 = date.today() + timedelta(days=1) # Tomorrow
|
t0 = date.today() + timedelta(days=1) # Tomorrow
|
||||||
daily = weekly = monthly = 0
|
daily = weekly = monthly = yearly = 0
|
||||||
for archive in archives:
|
for archive in archives:
|
||||||
|
if args.prefix and not archive.name.startswith(args.prefix):
|
||||||
|
continue
|
||||||
t = to_localtime(archive.ts).date()
|
t = to_localtime(archive.ts).date()
|
||||||
if daily < args.daily and t < t0:
|
if daily < args.daily and t < t0:
|
||||||
daily += 1
|
daily += 1
|
||||||
self.print_verbose('Archive "%s" is daily archive number %d',
|
self.print_verbose('Archive "%s" is daily archive number %d',
|
||||||
archive.metadata['name'], daily)
|
archive.name, daily)
|
||||||
t0 = t
|
t0 = t
|
||||||
elif weekly < args.weekly and t < t0 and t.weekday() == 1:
|
elif weekly < args.weekly and t < t0 and t.weekday() == 1:
|
||||||
weekly += 1
|
weekly += 1
|
||||||
self.print_verbose('Archive "%s" is weekly archive number %d',
|
self.print_verbose('Archive "%s" is weekly archive number %d',
|
||||||
archive.metadata['name'], weekly)
|
archive.name, weekly)
|
||||||
t0 = t
|
t0 = t
|
||||||
elif monthly < args.monthly and t < t0 and t.day == 1:
|
elif monthly < args.monthly and t < t0 and t.day == 1:
|
||||||
num_weekly += 1
|
monthly += 1
|
||||||
self.print_verbose('Archive "%s" is monthly archive number %d',
|
self.print_verbose('Archive "%s" is monthly archive number %d',
|
||||||
archive.metadata['name'], monthly)
|
archive.name, monthly)
|
||||||
|
t0 = t
|
||||||
|
elif yearly < args.yearly and t < t0 and day_of_year(t) == 1:
|
||||||
|
yearly += 1
|
||||||
|
self.print_verbose('Archive "%s" is yearly archive number %d',
|
||||||
|
archive.name, yearly)
|
||||||
t0 = t
|
t0 = t
|
||||||
else:
|
else:
|
||||||
self.print_verbose('Purging archive %s', archive.metadata['name'])
|
self.print_verbose('Purging archive %s', archive.name)
|
||||||
if args.really:
|
if args.really:
|
||||||
archive.delete(cache)
|
archive.delete(cache)
|
||||||
else:
|
else:
|
||||||
|
@ -346,6 +354,10 @@ class Archiver(object):
|
||||||
help='Number of daily archives to keep')
|
help='Number of daily archives to keep')
|
||||||
subparser.add_argument('-m', '--monthly', dest='monthly', type=int, default=0,
|
subparser.add_argument('-m', '--monthly', dest='monthly', type=int, default=0,
|
||||||
help='Number of monthly archives to keep')
|
help='Number of monthly archives to keep')
|
||||||
|
subparser.add_argument('-y', '--yearly', dest='yearly', type=int, default=0,
|
||||||
|
help='Number of yearly archives to keep')
|
||||||
|
subparser.add_argument('-p', '--prefix', dest='prefix', type=str,
|
||||||
|
help='Only consider archive names starting with this prefix')
|
||||||
subparser.add_argument('-r', '--really', dest='really',
|
subparser.add_argument('-r', '--really', dest='really',
|
||||||
action='store_true', default=False,
|
action='store_true', default=False,
|
||||||
help='Actually delete archives')
|
help='Actually delete archives')
|
||||||
|
|
|
@ -12,6 +12,12 @@ import sys
|
||||||
import time
|
import time
|
||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
|
|
||||||
|
def day_of_year(d):
|
||||||
|
"""Calculate the "day of year" from a date object"""
|
||||||
|
return int(d.strftime('%j'))
|
||||||
|
|
||||||
|
|
||||||
# OSX filenames are UTF-8 Only so any non-utf8 filenames are url encoded
|
# OSX filenames are UTF-8 Only so any non-utf8 filenames are url encoded
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == 'darwin':
|
||||||
def encode_filename(name):
|
def encode_filename(name):
|
||||||
|
@ -23,6 +29,7 @@ if sys.platform == 'darwin':
|
||||||
else:
|
else:
|
||||||
encode_filename = str
|
encode_filename = str
|
||||||
|
|
||||||
|
|
||||||
class Counter(object):
|
class Counter(object):
|
||||||
|
|
||||||
__slots__ = ('v',)
|
__slots__ = ('v',)
|
||||||
|
@ -48,6 +55,7 @@ def get_keys_dir():
|
||||||
return os.environ.get('DARC_KEYS_DIR',
|
return os.environ.get('DARC_KEYS_DIR',
|
||||||
os.path.join(os.path.expanduser('~'), '.darc', 'keys'))
|
os.path.join(os.path.expanduser('~'), '.darc', 'keys'))
|
||||||
|
|
||||||
|
|
||||||
def get_cache_dir():
|
def get_cache_dir():
|
||||||
"""Determine where to store keys and cache"""
|
"""Determine where to store keys and cache"""
|
||||||
return os.environ.get('DARC_CACHE_DIR',
|
return os.environ.get('DARC_CACHE_DIR',
|
||||||
|
@ -69,14 +77,17 @@ def deferrable(f):
|
||||||
return f(*args, **kw)
|
return f(*args, **kw)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
def error_callback(res, error, data):
|
def error_callback(res, error, data):
|
||||||
if res:
|
if res:
|
||||||
raise res
|
raise res
|
||||||
|
|
||||||
|
|
||||||
def to_localtime(ts):
|
def to_localtime(ts):
|
||||||
"""Convert datetime object from UTC to local time zone"""
|
"""Convert datetime object from UTC to local time zone"""
|
||||||
return ts - timedelta(seconds=time.altzone)
|
return ts - timedelta(seconds=time.altzone)
|
||||||
|
|
||||||
|
|
||||||
def read_set(path):
|
def read_set(path):
|
||||||
"""Read set from disk (as int32s)
|
"""Read set from disk (as int32s)
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Add table
Reference in a new issue