#!/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 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_false", 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 # 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: