From 6e650c1c9ff3dbda7f95883dd5343b53a284ab5a Mon Sep 17 00:00:00 2001 From: Silvie Chlupova Date: Apr 14 2021 13:26:08 +0000 Subject: [PATCH 1/2] Move prunerepo to helpers.py --- diff --git a/prunerepo b/prunerepo deleted file mode 100755 index 9963840..0000000 --- a/prunerepo +++ /dev/null @@ -1,194 +0,0 @@ -#!/usr/bin/python3 - -import subprocess -import sys -import argparse -import os -import re -import time -import shutil - -parser = argparse.ArgumentParser(description='Remove old packages from rpm-md repository') - -parser.add_argument('path', action='store', - help='local path to a yum repository') -parser.add_argument('--days', type=int, action='store', default=0, - help='only remove packages (and build directories when --cleancopr is used)\ - that are DAYS old or older (for packages by their build date, for directories\ - the last modification time is considered') -parser.add_argument('--cleancopr', action='store_true', - help='additionaly remove whole copr build dirs and logs if the associated package gets deleted') -parser.add_argument('--alwayscreaterepo', action='store_true', - help='Recreate repository even when there was no change in data.') -parser.add_argument('--nocreaterepo', action='store_true', - help='repository is not automatically recreated (not even after data deletion). Supresses --alwayscreaterepo.') -parser.add_argument('--verbose', action='store_true', - help='print all deleted items to stdout') -parser.add_argument('--quiet', action='store_true', - help='do not print any info messages, just do your job') -parser.add_argument('--dry-run', action='store_true', - help='do not remove anything from the repository and print the actions instead') -parser.add_argument('-v', '--version', action='version', version='1.5', - help='print program version and exit') - -args = parser.parse_args() -if args.dry_run: - args.verbose = True - - -get_all_packages_cmd = [ - 'dnf', - 'repoquery', - '--repofrompath=prunerepo_query,'+os.path.abspath(args.path), - '--repo=prunerepo_query', - '--refresh', - '--queryformat=%{location}', - '--quiet', - '--setopt=skip_if_unavailable=False', -] - -get_latest_packages_cmd = get_all_packages_cmd + [ '--latest-limit=1' ] - - -def is_srpm(package): - return package.endswith(".src.rpm") - - -def rm_file(path): - """ - Remove file given its absolute path - """ - if args.verbose: - log_info("Removing: "+path) - if args.dry_run: - return - if os.path.exists(path) and os.path.isfile(path): - os.remove(path) - - -def log_info(msg): - if not args.quiet: - print(msg) - - -def run_cmd(cmd, silent=False, dry_run=False): - """ - Run given command in a subprocess - """ - if not silent: - log_info("Executing: "+' '.join(cmd)) - if dry_run: - return - process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (stdout, stderr) = process.communicate() - sys.stderr.write(stderr.decode(encoding='utf-8')) - if process.returncode != 0: - sys.exit(1) - return stdout.decode(encoding='utf-8').splitlines() - - -def get_package_build_time(package_path): - """ - Get build time by reading package metadata - """ - query_cmd = ['/usr/bin/rpm', '-qp', '--queryformat', '%{BUILDTIME}'] + [ package_path ] - stdout = run_cmd(query_cmd, silent=True) - return int(stdout[0]) - - -def get_rpms(repoquery_cmd): - """ - Get paths to rpm packages in the repository according to given repoquery_cmd - """ - stdout = run_cmd(repoquery_cmd) # returns srpms as well - rel_rpms_paths = [relpath for relpath in stdout if not is_srpm(relpath)] - abs_rpms_paths = [os.path.abspath(os.path.join(args.path, relpath)) for relpath in rel_rpms_paths] - return abs_rpms_paths - - -def rm_srpm(rpm): - """ - If there is matching srpm in the same directory as given rpm (described by its absolute path), delete it - """ - get_srpm_cmd = get_all_packages_cmd + [ '--srpm', os.path.splitext(os.path.basename(rpm))[0] ] - output = run_cmd(get_srpm_cmd, silent=True) - if not output: - return - - srpm_name = os.path.basename(output[0]) - srpm_path = os.path.abspath(os.path.join(os.path.dirname(rpm), srpm_name)) - - if args.verbose: - log_info("Removing: " + srpm_path) - if args.dry_run: - return - rm_file(srpm_path) - - -def prune_packages(): - """ - Remove obsoleted packages - """ - log_info('Removing obsoleted packages...') - was_deletion = False - latest_rpms = get_rpms(get_latest_packages_cmd) - if not latest_rpms: - log_info("No RPMs available") - return was_deletion - all_rpms = get_rpms(get_all_packages_cmd) - to_remove_rpms = set(all_rpms) - set(latest_rpms) - for rpm in to_remove_rpms: - if time.time() - get_package_build_time(rpm) > args.days * 24 * 3600: - rm_srpm(rpm) - rm_file(rpm) - was_deletion = True - return was_deletion - - -def recreate_repo(): - """ - Recreate the repository by using createrepo_c - """ - log_info("Recreating repository...") - createrepo_cmd = ['/usr/bin/createrepo_c', '--database', '--update', '--local-sqlite', - '--cachedir', '/tmp/', '--workers', '8'] + [ args.path ] - return run_cmd(createrepo_cmd, dry_run=args.dry_run) - - -def clean_copr(): - """ - Remove whole copr build dirs if they no longer contain a srpm/rpm file - """ - log_info("This feature is deprecated and will be removed in a future release. Please, use a custom solution instead.") - log_info("Cleaning COPR repository...") - for dir_name in os.listdir(args.path): - dir_path = os.path.abspath(os.path.join(args.path, dir_name)) - - if not os.path.isdir(dir_path): - continue - if not os.path.isfile(os.path.join(dir_path, 'build.info')): - continue - if [item for item in os.listdir(dir_path) if re.match(r'.*\.rpm$', item)]: - continue - if time.time() - os.stat(dir_path).st_mtime <= args.days * 24 * 3600: - continue - - if args.verbose: - log_info('Removing: '+dir_path) - shutil.rmtree(dir_path) - - # also remove the associated log in the main dir - build_id = os.path.basename(dir_path).split('-')[0] - buildlog_name = 'build-' + build_id + '.log' - buildlog_path = os.path.abspath(os.path.join(args.path, buildlog_name)) - rm_file(os.path.join(args.path, buildlog_path)) - - -if __name__ == '__main__': - was_deletion = prune_packages() - if (was_deletion or args.alwayscreaterepo) \ - and not args.nocreaterepo: - recreate_repo() - - if args.cleancopr: - clean_copr() diff --git a/prunerepo/helpers.py b/prunerepo/helpers.py new file mode 100755 index 0000000..9963840 --- /dev/null +++ b/prunerepo/helpers.py @@ -0,0 +1,194 @@ +#!/usr/bin/python3 + +import subprocess +import sys +import argparse +import os +import re +import time +import shutil + +parser = argparse.ArgumentParser(description='Remove old packages from rpm-md repository') + +parser.add_argument('path', action='store', + help='local path to a yum repository') +parser.add_argument('--days', type=int, action='store', default=0, + help='only remove packages (and build directories when --cleancopr is used)\ + that are DAYS old or older (for packages by their build date, for directories\ + the last modification time is considered') +parser.add_argument('--cleancopr', action='store_true', + help='additionaly remove whole copr build dirs and logs if the associated package gets deleted') +parser.add_argument('--alwayscreaterepo', action='store_true', + help='Recreate repository even when there was no change in data.') +parser.add_argument('--nocreaterepo', action='store_true', + help='repository is not automatically recreated (not even after data deletion). Supresses --alwayscreaterepo.') +parser.add_argument('--verbose', action='store_true', + help='print all deleted items to stdout') +parser.add_argument('--quiet', action='store_true', + help='do not print any info messages, just do your job') +parser.add_argument('--dry-run', action='store_true', + help='do not remove anything from the repository and print the actions instead') +parser.add_argument('-v', '--version', action='version', version='1.5', + help='print program version and exit') + +args = parser.parse_args() +if args.dry_run: + args.verbose = True + + +get_all_packages_cmd = [ + 'dnf', + 'repoquery', + '--repofrompath=prunerepo_query,'+os.path.abspath(args.path), + '--repo=prunerepo_query', + '--refresh', + '--queryformat=%{location}', + '--quiet', + '--setopt=skip_if_unavailable=False', +] + +get_latest_packages_cmd = get_all_packages_cmd + [ '--latest-limit=1' ] + + +def is_srpm(package): + return package.endswith(".src.rpm") + + +def rm_file(path): + """ + Remove file given its absolute path + """ + if args.verbose: + log_info("Removing: "+path) + if args.dry_run: + return + if os.path.exists(path) and os.path.isfile(path): + os.remove(path) + + +def log_info(msg): + if not args.quiet: + print(msg) + + +def run_cmd(cmd, silent=False, dry_run=False): + """ + Run given command in a subprocess + """ + if not silent: + log_info("Executing: "+' '.join(cmd)) + if dry_run: + return + process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (stdout, stderr) = process.communicate() + sys.stderr.write(stderr.decode(encoding='utf-8')) + if process.returncode != 0: + sys.exit(1) + return stdout.decode(encoding='utf-8').splitlines() + + +def get_package_build_time(package_path): + """ + Get build time by reading package metadata + """ + query_cmd = ['/usr/bin/rpm', '-qp', '--queryformat', '%{BUILDTIME}'] + [ package_path ] + stdout = run_cmd(query_cmd, silent=True) + return int(stdout[0]) + + +def get_rpms(repoquery_cmd): + """ + Get paths to rpm packages in the repository according to given repoquery_cmd + """ + stdout = run_cmd(repoquery_cmd) # returns srpms as well + rel_rpms_paths = [relpath for relpath in stdout if not is_srpm(relpath)] + abs_rpms_paths = [os.path.abspath(os.path.join(args.path, relpath)) for relpath in rel_rpms_paths] + return abs_rpms_paths + + +def rm_srpm(rpm): + """ + If there is matching srpm in the same directory as given rpm (described by its absolute path), delete it + """ + get_srpm_cmd = get_all_packages_cmd + [ '--srpm', os.path.splitext(os.path.basename(rpm))[0] ] + output = run_cmd(get_srpm_cmd, silent=True) + if not output: + return + + srpm_name = os.path.basename(output[0]) + srpm_path = os.path.abspath(os.path.join(os.path.dirname(rpm), srpm_name)) + + if args.verbose: + log_info("Removing: " + srpm_path) + if args.dry_run: + return + rm_file(srpm_path) + + +def prune_packages(): + """ + Remove obsoleted packages + """ + log_info('Removing obsoleted packages...') + was_deletion = False + latest_rpms = get_rpms(get_latest_packages_cmd) + if not latest_rpms: + log_info("No RPMs available") + return was_deletion + all_rpms = get_rpms(get_all_packages_cmd) + to_remove_rpms = set(all_rpms) - set(latest_rpms) + for rpm in to_remove_rpms: + if time.time() - get_package_build_time(rpm) > args.days * 24 * 3600: + rm_srpm(rpm) + rm_file(rpm) + was_deletion = True + return was_deletion + + +def recreate_repo(): + """ + Recreate the repository by using createrepo_c + """ + log_info("Recreating repository...") + createrepo_cmd = ['/usr/bin/createrepo_c', '--database', '--update', '--local-sqlite', + '--cachedir', '/tmp/', '--workers', '8'] + [ args.path ] + return run_cmd(createrepo_cmd, dry_run=args.dry_run) + + +def clean_copr(): + """ + Remove whole copr build dirs if they no longer contain a srpm/rpm file + """ + log_info("This feature is deprecated and will be removed in a future release. Please, use a custom solution instead.") + log_info("Cleaning COPR repository...") + for dir_name in os.listdir(args.path): + dir_path = os.path.abspath(os.path.join(args.path, dir_name)) + + if not os.path.isdir(dir_path): + continue + if not os.path.isfile(os.path.join(dir_path, 'build.info')): + continue + if [item for item in os.listdir(dir_path) if re.match(r'.*\.rpm$', item)]: + continue + if time.time() - os.stat(dir_path).st_mtime <= args.days * 24 * 3600: + continue + + if args.verbose: + log_info('Removing: '+dir_path) + shutil.rmtree(dir_path) + + # also remove the associated log in the main dir + build_id = os.path.basename(dir_path).split('-')[0] + buildlog_name = 'build-' + build_id + '.log' + buildlog_path = os.path.abspath(os.path.join(args.path, buildlog_name)) + rm_file(os.path.join(args.path, buildlog_path)) + + +if __name__ == '__main__': + was_deletion = prune_packages() + if (was_deletion or args.alwayscreaterepo) \ + and not args.nocreaterepo: + recreate_repo() + + if args.cleancopr: + clean_copr() From 44f629b2a0b1d44b072297da31c8c4698dc13c06 Mon Sep 17 00:00:00 2001 From: Silvie Chlupova Date: Apr 16 2021 09:11:38 +0000 Subject: [PATCH 2/2] Start using functions from helpers Fixes: #9 --- diff --git a/man/prunerepo.1.asciidoc b/man/prunerepo.1.asciidoc index 8b19c21..0ce7bc0 100644 --- a/man/prunerepo.1.asciidoc +++ b/man/prunerepo.1.asciidoc @@ -8,7 +8,7 @@ prunerepo - remove old packages from rpm-md repository SYNOPSIS -------- -prunerepo [--days DAYS] [--cleancopr] [--nocreaterepo] [--verbose] [-h] [-v] path +prunerepo [--days DAYS] [--cleancopr] [--nocreaterepo] [--log-level LOG_LEVEL] [--dry-run] [-h] [-v] path DESCRIPTION @@ -37,20 +37,23 @@ path:: OPTIONS ------- --days DAYS:: - only remove packages that are DAYS old or older by their build date. This option also affects subsequent deletion of build directories with no rpm or srpm inside when --cleancopr is used. - These directories are deleted only if their latest modification time is more than DAYS in past. + only remove packages (and build directories when --cleancopr is used) that are DAYS old or older + (for packages by their build date, for directories the last modification time is considered) --cleancopr:: - additionally remove whole copr build dirs (contain 'build.info' file) and logs if the associated package gets deleted + additionally remove whole copr build dirs and logs if the associated package gets deleted + +--alwayscreaterepo:: + Recreate repository even when there was no change in data --nocreaterepo:: - repository is not automatically recreated after deletion + repository is not automatically recreated (not even after data deletion). Supresses --alwayscreaterepo. ---verbose:: - print all deleted items to stdout +--log-level:: + set logging to desired level ---verbose:: - do not print any info messages, just do your job +--dry-run:: + do not remove anything from the repository and print the actions instead. Verbose mode will be set. -h, --help:: show this help message and exit diff --git a/prunerepo.spec b/prunerepo.spec index 93ed9ca..4f7a884 100644 --- a/prunerepo.spec +++ b/prunerepo.spec @@ -14,7 +14,7 @@ BuildArch: noarch BuildRequires: bash BuildRequires: python3-devel BuildRequires: python3-setuptools -BuildRequires: rpm-python3 +BuildRequires: python3-rpm BuildRequires: createrepo_c BuildRequires: asciidoc BuildRequires: findutils @@ -23,7 +23,7 @@ BuildRequires: dnf-plugins-core BuildRequires: coreutils Requires: createrepo_c Requires: dnf-plugins-core -Requires: rpm-python3 +Requires: python3-rpm Requires: python3 %description diff --git a/prunerepo/__init__.py b/prunerepo/__init__.py new file mode 100644 index 0000000..7c17009 --- /dev/null +++ b/prunerepo/__init__.py @@ -0,0 +1 @@ +from .helpers import get_rpms_to_remove diff --git a/prunerepo/helpers.py b/prunerepo/helpers.py index 9963840..8477fb2 100755 --- a/prunerepo/helpers.py +++ b/prunerepo/helpers.py @@ -2,81 +2,35 @@ import subprocess import sys -import argparse import os import re import time import shutil +import logging -parser = argparse.ArgumentParser(description='Remove old packages from rpm-md repository') - -parser.add_argument('path', action='store', - help='local path to a yum repository') -parser.add_argument('--days', type=int, action='store', default=0, - help='only remove packages (and build directories when --cleancopr is used)\ - that are DAYS old or older (for packages by their build date, for directories\ - the last modification time is considered') -parser.add_argument('--cleancopr', action='store_true', - help='additionaly remove whole copr build dirs and logs if the associated package gets deleted') -parser.add_argument('--alwayscreaterepo', action='store_true', - help='Recreate repository even when there was no change in data.') -parser.add_argument('--nocreaterepo', action='store_true', - help='repository is not automatically recreated (not even after data deletion). Supresses --alwayscreaterepo.') -parser.add_argument('--verbose', action='store_true', - help='print all deleted items to stdout') -parser.add_argument('--quiet', action='store_true', - help='do not print any info messages, just do your job') -parser.add_argument('--dry-run', action='store_true', - help='do not remove anything from the repository and print the actions instead') -parser.add_argument('-v', '--version', action='version', version='1.5', - help='print program version and exit') - -args = parser.parse_args() -if args.dry_run: - args.verbose = True - - -get_all_packages_cmd = [ - 'dnf', - 'repoquery', - '--repofrompath=prunerepo_query,'+os.path.abspath(args.path), - '--repo=prunerepo_query', - '--refresh', - '--queryformat=%{location}', - '--quiet', - '--setopt=skip_if_unavailable=False', -] - -get_latest_packages_cmd = get_all_packages_cmd + [ '--latest-limit=1' ] +log = logging.getLogger(__name__) def is_srpm(package): return package.endswith(".src.rpm") -def rm_file(path): +def rm_file(path, dry_run): """ Remove file given its absolute path """ - if args.verbose: - log_info("Removing: "+path) - if args.dry_run: + log.info("Removing: " + path) + if dry_run: return if os.path.exists(path) and os.path.isfile(path): os.remove(path) -def log_info(msg): - if not args.quiet: - print(msg) - - -def run_cmd(cmd, silent=False, dry_run=False): +def run_cmd(cmd, dry_run): """ Run given command in a subprocess """ - if not silent: - log_info("Executing: "+' '.join(cmd)) + log.debug("Executing: " + ' '.join(cmd)) if dry_run: return process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) @@ -87,82 +41,76 @@ def run_cmd(cmd, silent=False, dry_run=False): return stdout.decode(encoding='utf-8').splitlines() -def get_package_build_time(package_path): +def get_package_build_time(package_path, dry_run): """ Get build time by reading package metadata """ - query_cmd = ['/usr/bin/rpm', '-qp', '--queryformat', '%{BUILDTIME}'] + [ package_path ] - stdout = run_cmd(query_cmd, silent=True) + query_cmd = ["/usr/bin/rpm", "-qp", "--queryformat", "%{BUILDTIME}"] + [package_path] + stdout = run_cmd(query_cmd, dry_run) return int(stdout[0]) -def get_rpms(repoquery_cmd): +def get_rpms(repoquery_cmd, path, dry_run): """ Get paths to rpm packages in the repository according to given repoquery_cmd """ - stdout = run_cmd(repoquery_cmd) # returns srpms as well + stdout = run_cmd(repoquery_cmd, dry_run) # returns srpms as well rel_rpms_paths = [relpath for relpath in stdout if not is_srpm(relpath)] - abs_rpms_paths = [os.path.abspath(os.path.join(args.path, relpath)) for relpath in rel_rpms_paths] + abs_rpms_paths = [os.path.abspath(os.path.join(path, relpath)) for relpath in rel_rpms_paths] return abs_rpms_paths -def rm_srpm(rpm): +def get_srpm(rpm, get_all_packages_cmd, dry_run): """ - If there is matching srpm in the same directory as given rpm (described by its absolute path), delete it + Get matching srpm in the same directory as given rpm (described by its absolute path) """ - get_srpm_cmd = get_all_packages_cmd + [ '--srpm', os.path.splitext(os.path.basename(rpm))[0] ] - output = run_cmd(get_srpm_cmd, silent=True) + get_srpm_cmd = get_all_packages_cmd + ["--srpm", os.path.splitext(os.path.basename(rpm))[0]] + output = run_cmd(get_srpm_cmd, dry_run) if not output: return srpm_name = os.path.basename(output[0]) srpm_path = os.path.abspath(os.path.join(os.path.dirname(rpm), srpm_name)) - - if args.verbose: - log_info("Removing: " + srpm_path) - if args.dry_run: - return - rm_file(srpm_path) + return srpm_path -def prune_packages(): +def prune_packages(path, days, log_level, dry_run): """ Remove obsoleted packages """ - log_info('Removing obsoleted packages...') + if not set_logging_level(log_level): + sys.exit(1) + log.debug('Removing obsoleted packages...') + rpms = get_rpms_to_remove(path, log_level, days) was_deletion = False - latest_rpms = get_rpms(get_latest_packages_cmd) - if not latest_rpms: - log_info("No RPMs available") + if not rpms: + log.error("No RPMs available") return was_deletion - all_rpms = get_rpms(get_all_packages_cmd) - to_remove_rpms = set(all_rpms) - set(latest_rpms) - for rpm in to_remove_rpms: - if time.time() - get_package_build_time(rpm) > args.days * 24 * 3600: - rm_srpm(rpm) - rm_file(rpm) - was_deletion = True + for rpm in rpms: + rm_file(rpm, dry_run) + was_deletion = True return was_deletion -def recreate_repo(): +def recreate_repo(path, dry_run): """ Recreate the repository by using createrepo_c """ - log_info("Recreating repository...") + log.debug("Recreating repository...") createrepo_cmd = ['/usr/bin/createrepo_c', '--database', '--update', '--local-sqlite', - '--cachedir', '/tmp/', '--workers', '8'] + [ args.path ] - return run_cmd(createrepo_cmd, dry_run=args.dry_run) + '--cachedir', '/tmp/', '--workers', '8'] + [path] + return run_cmd(createrepo_cmd, dry_run) -def clean_copr(): +def clean_copr(path, days, dry_run): """ Remove whole copr build dirs if they no longer contain a srpm/rpm file """ - log_info("This feature is deprecated and will be removed in a future release. Please, use a custom solution instead.") - log_info("Cleaning COPR repository...") - for dir_name in os.listdir(args.path): - dir_path = os.path.abspath(os.path.join(args.path, dir_name)) + log.info("This feature is deprecated and will be removed in a future release. " + "Please, use a custom solution instead.") + log.info("Cleaning COPR repository...") + for dir_name in os.listdir(path): + dir_path = os.path.abspath(os.path.join(path, dir_name)) if not os.path.isdir(dir_path): continue @@ -170,25 +118,73 @@ def clean_copr(): continue if [item for item in os.listdir(dir_path) if re.match(r'.*\.rpm$', item)]: continue - if time.time() - os.stat(dir_path).st_mtime <= args.days * 24 * 3600: + if time.time() - os.stat(dir_path).st_mtime <= days * 24 * 3600: continue - if args.verbose: - log_info('Removing: '+dir_path) + log.info('Removing: ' + dir_path) shutil.rmtree(dir_path) # also remove the associated log in the main dir build_id = os.path.basename(dir_path).split('-')[0] buildlog_name = 'build-' + build_id + '.log' - buildlog_path = os.path.abspath(os.path.join(args.path, buildlog_name)) - rm_file(os.path.join(args.path, buildlog_path)) - - -if __name__ == '__main__': - was_deletion = prune_packages() - if (was_deletion or args.alwayscreaterepo) \ - and not args.nocreaterepo: - recreate_repo() - - if args.cleancopr: - clean_copr() + buildlog_path = os.path.abspath(os.path.join(path, buildlog_name)) + rm_file(os.path.join(path, buildlog_path), dry_run) + + +def set_logging_level(log_level): + """ + Set logging level + """ + handler = logging.StreamHandler(stream=sys.stderr) + handler.setFormatter(logging.Formatter("%(message)s")) + try: + handler.setLevel(log_level.upper()) + log.addHandler(handler) + log.setLevel(handler.level) + return True + except ValueError as error: + print(str(error), file=sys.stderr) + except TypeError as error: + print(str(error), file=sys.stderr) + return False + + +def get_rpms_to_remove(directory, log_level='INFO', days=0): + """ + Returns a list of (s)rpm path names that should be removed. + 0 days means that (s)rpm will be removed regardless of when the package was built. + + :param directory: local path to a yum repository + :param log_level: set logging to desired level (error, info or debug) + :param days: how old are the packages to be removed, in the number of days + :return: a list of (s)RPM path names that should be removed + """ + get_all_packages_cmd = [ + "dnf", + "repoquery", + "--repofrompath=prunerepo_query," + os.path.abspath(directory), + "--repo=prunerepo_query", + "--refresh", + "--queryformat=%{location}", + "--quiet", + "--setopt=skip_if_unavailable=False", + ] + if not log.handlers: + if not set_logging_level(log_level): + return [] + log.info("Checking '%s' directory for removal candidates older than %s days" % (os.path.abspath(directory), days)) + get_latest_packages_cmd = get_all_packages_cmd + ['--latest-limit=1'] + latest_rpms = get_rpms(get_latest_packages_cmd, directory, dry_run=False) + if not latest_rpms: + return [] + all_rpms = get_rpms(get_all_packages_cmd, directory, dry_run=False) + to_remove_rpms = set(all_rpms) - set(latest_rpms) + rpm_list = [] + for rpm in to_remove_rpms: + log.debug("Checking age of the '%s' file" % os.path.split(rpm)[1]) + if time.time() - get_package_build_time(rpm, dry_run=False) > days * 24 * 3600: + srpm = get_srpm(rpm, get_all_packages_cmd, dry_run=False) + if srpm: + rpm_list.append(srpm) + rpm_list.append(rpm) + return rpm_list diff --git a/prunerepo/main.py b/prunerepo/main.py new file mode 100755 index 0000000..7059663 --- /dev/null +++ b/prunerepo/main.py @@ -0,0 +1,48 @@ +#!/usr/bin/python3 + +import argparse + +from prunerepo.helpers import prune_packages, recreate_repo, clean_copr + + +def get_parser(): + parser = argparse.ArgumentParser(description='Remove old packages from rpm-md repository') + parser.add_argument('path', action='store', + help='local path to a yum repository') + parser.add_argument('--days', type=int, action='store', default=0, + help='only remove packages (and build directories when --cleancopr is used)\ + that are DAYS old or older (for packages by their build date, for directories\ + the last modification time is considered') + parser.add_argument('--cleancopr', action='store_true', + help='additionaly remove whole copr build dirs and logs if the associated package gets deleted') + parser.add_argument('--alwayscreaterepo', action='store_true', + help='Recreate repository even when there was no change in data.') + parser.add_argument('--nocreaterepo', action='store_true', + help='repository is not automatically recreated (not even after data deletion). ' + 'Supresses --alwayscreaterepo.') + parser.add_argument('--log-level', type=str, default='INFO', + help='set logging to desired level') + parser.add_argument('--dry-run', action='store_true', + help='do not remove anything from the repository and print the actions instead. ' + 'Verbose mode will be set.') + parser.add_argument('-v', '--version', action='version', version='1.5', + help='print program version and exit') + + args = parser.parse_args() + if args.dry_run: + args.log_level = 'DEBUG' + return args + + +def main(): + args = get_parser() + was_deletion = prune_packages(args.path, args.days, args.log_level, args.dry_run) + if (was_deletion or args.alwayscreaterepo) and not args.nocreaterepo: + recreate_repo(args.path, args.dry_run) + + if args.cleancopr: + clean_copr(args.path, args.days, args.dry_run) + + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index 8cc6902..b301925 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ import os -from setuptools import setup +from setuptools import setup, find_packages setup( name=os.getenv('name'), @@ -17,6 +17,10 @@ setup( "Programming Language :: Python :: 3", "Topic :: Software Development :: Build Tools", ], - scripts=['prunerepo'], + entry_points={ + 'console_scripts': [ + 'prunerepo=prunerepo.main:main'], + }, include_package_data=True, + packages=find_packages(), ) diff --git a/tests/testlib.sh b/tests/testlib.sh index b48beca..4b7e9e5 100644 --- a/tests/testlib.sh +++ b/tests/testlib.sh @@ -1,11 +1,12 @@ export libdir="$(builtin cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)" +export PYTHONPATH="$libdir/../" die() { echo "fail."; exit 1; } function runcmd { - bash -c "set -x; $libdir/../prunerepo --verbose $*;" + python3 "$libdir/../prunerepo/main.py" "$@" --log-level "DEBUG" } function listpkgsbyrepo {