# -*- coding: utf-8 -*-
# pylint: disable=I0011,C0103
""" rTorrent Disk Space House-Keeping.
This is used in the ``rtsweep`` tool and the queue job of the
``pyrotoque`` daemon to free up disk space for new items, by
deleting old items in a controlled way using a configurable order.
Copyright (c) 2018 The PyroScope Project <pyroscope.project@gmail.com>
"""
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from __future__ import with_statement
from __future__ import absolute_import
from collections import namedtuple
from pyrocore import error
from pyrocore import config as config_ini
from pyrocore.torrent import engine, matching
SweepRule = namedtuple('SweepRule', 'ruleset name prio order filter')
[docs]def parse_cond(text):
"""Parse a filter condition."""
return matching.ConditionParser(engine.FieldDefinition.lookup, "name").parse(text)
[docs]class DiskSpaceManager(object):
"""Core implementation of ``rtsweep``."""
def __init__(self, config=None, rulesets=None):
self.config = config or config_ini
self.active_rulesets = rulesets or [x.strip() for x in self.config.sweep['default_rules'].split(',')]
self.rules = []
self.default_order = self.config.sweep['default_order']
self.protected = parse_cond(self.config.sweep['filter_protected'])
self._load_rules()
def _load_rules(self):
"""Load rule definitions from config."""
for ruleset in self.active_rulesets:
section_name = 'sweep_rules_' + ruleset.lower()
try:
ruledefs = getattr(self.config, section_name)
except AttributeError:
raise error.UserError("There is no [{}] section in your configuration"
.format(section_name.upper()))
for ruledef, filtercond in ruledefs.items():
if ruledef.endswith('.filter'):
rulename = ruledef.rsplit('.', 1)[0]
rule = SweepRule(ruleset, rulename,
int(ruledefs.get(rulename + '.prio', '999')),
ruledefs.get(rulename + '.order', self.default_order),
parse_cond(filtercond))
self.rules.append(rule)
self.rules.sort(key=lambda x: (x.prio, x.name))
return self.rules
# test "$1" = "--aggressive" && { shift; activity=5i; } || activity=4h
# $DRY ~/bin/rtcontrol -/1 --cull active=+$activity [ NOT [ $PROTECTED ] ] \
# -qco loaded,size.sz,uploaded.sz,seedtime,ratio,name "$@" $INTERACTIVE; rc=$?
# log.debug("No matches for {ruleset}
##needed=$(( $requested + $RESERVED_GiB * $GiB )) # Add a few GiB for the system
##log.info"Disk space management started [with $(print_gib $(download_free)) free]")
# Finally, go through everything sorted by age (with staged activity protection)
## -s loaded //
## --aggressive -s loaded //
# $INFO "Disk space management finished in ${took_secs}s [$(print_gib $(download_free)) free," \
# "$(print_gib $requested) requested]"
# $INFO "Removed $(( $start_items - $after_items )) item(s)," \
# "freeing $(print_gib $(( $after_free - $start_free ))) disk space" \
# "[now $(print_gib $(download_free)) free, took ${took_secs}s]."