#!/usr/bin/python3 # coding: utf-8 # archversion - Archlinux Version Controller # Copyright © 2012 Sébastien Luttringer # # 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. '''Archlinux Version Controller''' from archversion import VERSION, CONFIG_SENDMAIL from archversion.config import BaseConfigFile from archversion.error import BaseError, MissingConfigFile, NoSuchFile from archversion.error import ERR_FATAL, ERR_ABORT, ERR_UNKNOWN from archversion.pacman import parse_pkgbuild, pkgbuild_set_version, pkgbuild_update_checksums from archversion.version import VersionController from email.mime.text import MIMEText from email.utils import formatdate from io import StringIO from smtplib import SMTP import argparse import logging import os import sys def parse_argv(): '''Parse command line arguments''' p_main = argparse.ArgumentParser() p_main.add_argument("--version", action="version", version="%(prog)s version " + VERSION) p_main.add_argument("--debug", action="store_true", help="debug mode") sp_main = p_main.add_subparsers() # config parser p_conf = sp_main.add_parser("config", help="list configured packages") p_conf.add_argument("-s", "--sort", action="store_true", help="sort listing") p_conf.add_argument("packages", nargs='*', help="only check these packages") p_conf.set_defaults(func=command_config) # sync parser p_sync = sp_main.add_parser("sync", help="retrieve upstream and dowstream versions") p_sync.add_argument("-s", "--sort", action="store_true", help="sort syncing") p_sync.add_argument("packages", nargs='*', help="only sync these packages") p_sync.set_defaults(func=command_sync) # modes parser p_modes = sp_main.add_parser("modes", help="list check against modes") p_modes.set_defaults(func=command_modes) # report parser p_report = sp_main.add_parser("report", help="report packages versions") p_report.add_argument("-f", "--fresh", action="store_true", help="Only report fresh versions") p_report.add_argument("-n", "--new", action="store_true", help="Only report new versions") p_report.add_argument("-s", "--sort", action="store_true", help="sort packages by name") p_report.add_argument("-S", "--sync", action="store_true", help="sync packages versions before report") p_report.add_argument("packages", nargs='*', help="only report these packages") p_report.set_defaults(func=command_report) # check parser p_check = sp_main.add_parser("check", help="check packages versions") p_check.add_argument("-f", "--fresh", action="store_true", help="Only report fresh versions") p_check.add_argument("-n", "--new", action="store_true", help="Only report new versions") p_check.add_argument("-s", "--sort", action="store_true", help="sort packages by name") p_check.add_argument("packages", nargs='*', help="only check these packages") p_check.set_defaults(func=command_check) # sendmail parser p_sendmail = sp_main.add_parser("sendmail", help="sendmail packages versions by mail") p_sendmail.add_argument("-f", "--fresh", action="store_true", help="Only sendmail fresh versions") p_sendmail.add_argument("-n", "--new", action="store_true", help="Only sendmail new versions") p_sendmail.add_argument("-s", "--sort", action="store_true", help="sort packages by name") p_sendmail.add_argument("-S", "--sync", action="store_true", help="sync packages versions before sendmail") p_sendmail.add_argument("--to", help="mail destination address") p_sendmail.add_argument("--smtp", help="smtp server") p_sendmail.add_argument("packages", nargs='*', help="only sendmail these packages") p_sendmail.set_defaults(func=command_sendmail) # update parser p_update = sp_main.add_parser("update", help="update a PKGBUILD with the latest version") p_update.add_argument("-p", "--path", default="PKGBUILD", help="name of the file to update. Default PKGBUILD") p_update.add_argument("-c", "--checksum", action="store_true", help="run updpkgsums after update") p_update.add_argument("-S", "--no-sync", action="store_true", help="don't sync packages versions prior update") p_update.set_defaults(func=command_update) # do parse namespace = p_main.parse_args() # Ensure subparser was choosen if "func" not in namespace: p_main.error("missing argument") return namespace def command_config(args, vctrl): '''list configured packages''' if len(args.packages) > 0: vctrl.reduce_packages(args.packages) if args.sort: vctrl.sort_packages() vctrl.print_names() def command_modes(args, vctrl): '''list checking against modes''' vctrl.print_modes() def command_sync(args, vctrl): '''Handle sync command call''' # reduce the package list if len(args.packages) > 0: vctrl.reduce_packages(args.packages) # sort packages if asked if args.sort: vctrl.sort_packages() # start syncing vctrl.sync_packages() def command_check(args, vctrl): '''Handle check command call''' # reduce the package list args.sync=True command_report(args, vctrl) def command_report(args, vctrl): '''Handle report command call''' # reduce the package list if len(args.packages) > 0: vctrl.reduce_packages(args.packages) # sort packages if asked if args.sort: vctrl.sort_packages() # sync if asked if args.sync: vctrl.sync_packages() # start report vctrl.print_versions(args.new, args.fresh) def command_sendmail(args, vctrl): '''Handle sendmail command call''' # load sendmail config config = BaseConfigFile(CONFIG_SENDMAIL) # check args try: to = config["mail"]["to"] subject = config["mail"]["subject"] smtp = config["smtp"]["host"] except KeyError as exp: logging.error("Invalid sendmail config: %s" % exp) exit(1) # capture a report stdout = StringIO() stdout_bak = sys.stdout sys.stdout = stdout command_report(args, vctrl) sys.stdout = stdout_bak # no data, no mail! if len(stdout.getvalue()) == 0: return # format the mail msg = MIMEText(stdout.getvalue()) msg["Subject"] = subject msg["From"] = "Archversion " msg["To"] = to msg["Date"] = formatdate(localtime=True) # send the mail try: s = SMTP(smtp) s.send_message(msg) s.quit() except Exception as exp: logging.error("Sendmail fail: %s" % exp) exit(1) def command_update(args, vctrl): '''Handle update command call''' if not os.path.exists(args.path): raise NoSuchFile(args.path) if os.getresuid()[1] == 0: logging.warn("Warning: You should not run this as root") pkgdict = parse_pkgbuild(args.path) pkgname = pkgdict.get("pkgname0", pkgdict.get("pkgbase", None)) pkgver = pkgdict.get("pkgver", None) # some sanity checks if pkgname is None: raise BaseError("Unable to detect pkgname in %s" % args.path) if pkgver is None: raise BaseError("Unable to detect pkgver in %s" % args.path) if pkgname not in vctrl.packages: raise BaseError("No registered package %s" % pkgname) # redure packge list to the extracted one vctrl.reduce_packages((pkgname,)) # sync if not refused if not args.no_sync: vctrl.sync_packages() # get upstream version upver = vctrl.cache["upstream"].get(pkgname, {}).get("version", None) if upver is None: raise BaseError("Unable to detect upstream version of %s" % pkgname) # print what we detect print("Package name: %s" % pkgname) print("PKGBUILD version: %s" % pkgver) print("Upstream version: %s" % upver) # compare version if pkgver == upver: print("Version are the same. Do nothing!") return # update version with upstream pkgbuild_set_version(args.path, upver) # update checksum if args.checksum: pkgbuild_update_checksums(args.path) def main(): '''Program entry point''' try: # parse command line args = parse_argv() # set global debug mode if args.debug: logging.getLogger().setLevel(logging.DEBUG) # load controller vctrl = VersionController() # call command function return args.func(args, vctrl) except KeyboardInterrupt: exit(ERR_ABORT) except BaseError as exp: logging.error(exp) exit(ERR_FATAL) except Exception as exp: logging.error("Unknown error. Please report it with --debug.") logging.error(exp) if logging.getLogger().getEffectiveLevel() == logging.DEBUG: raise exit(ERR_UNKNOWN) if __name__ == '__main__': main() # vim:set ts=4 sw=4 et ai: